---
title: Convert continuous aggregates to the columnstore | Tiger Data Docs
description: Compress a continuous aggregate to the columnstore to save storage space while making sure the data is still available for your analytical workloads
---

Since [2.20.0](https://github.com/timescale/timescaledb/releases/tag/2.20.0)

To save on storage costs, you use hypercore to downsample historical data stored in continuous aggregates. After you [enable hypercore](/docs/reference/timescaledb/continuous-aggregates/alter_materialized_view/index.md) on a `MATERIALIZED VIEW`, you set a [columnstore policy](/docs/reference/timescaledb/hypercore/add_columnstore_policy/index.md). This policy defines the intervals when TimescaleDB converts chunks in a continuous aggregate from the rowstore to the columnstore.

Columnstore works in the same way on [hypertables and continuous aggregates](/docs/learn/columnar-storage/understand-hypercore/index.md). When you enable columnstore with no other options, your data is [segmented by](/docs/reference/timescaledb/continuous-aggregates/alter_materialized_view#arguments/index.md) the `groupby` columns in the continuous aggregate, and [ordered by](/docs/reference/timescaledb/continuous-aggregates/alter_materialized_view#arguments/index.md) the time column. [Real-time aggregate](/docs/learn/continuous-aggregates/real-time-aggregates/index.md) is disabled by default.

## Configure columnstore on continuous aggregates

For an [existing continuous aggregate](/docs/build/continuous-aggregates/create-a-continuous-aggregate/index.md):

1. **Enable hypercore on a continuous aggregate**

   Set `timescaledb.enable_columnstore = true` when you alter the view:

   ```
   ALTER MATERIALIZED VIEW <cagg_name> set (timescaledb.enable_columnstore = true);
   ```

   To disable hypercore, set `timescaledb.enable_columnstore = false`.

2. **Set the columnstore policy on the continuous aggregate**

   Before you set up a columnstore policy on a continuous aggregate, you first set the [refresh policy](/docs/build/continuous-aggregates/refresh-policies/index.md). To prevent refresh policies from failing, set the columnstore policy interval so that TimescaleDB does not convert actively refreshed regions to the columnstore. For example:

   1. Set the refresh policy:

      ```
      SELECT add_continuous_aggregate_policy('<cagg_name>',
        start_offset => INTERVAL '30 days',
        end_offset => INTERVAL '1 day',
        schedule_interval => INTERVAL '1 hour');
      ```

   2. Set the columnstore policy. The `after` parameter should be greater than the value of `start_offset` in the refresh policy:

      ```
      CALL add_columnstore_policy('<cagg_name>', after => INTERVAL '45 days');
      ```

## Convert refreshed chunks to the columnstore during refresh

Since [2.27.0](https://github.com/timescale/timescaledb/releases/tag/2.27.0)

As an alternative to a separate columnstore policy, you can configure the refresh policy itself to move continuous aggregate chunks into the columnstore after each refresh. Use this when you want refreshed data to land in the columnstore on the same schedule as the refresh, with no gap between the two windows.

When you enable `compress_after_refresh` on the refresh policy job, TimescaleDB converts the continuous aggregate chunks in the refresh window to the columnstore at the end of each scheduled refresh. TimescaleDB processes each chunk in its own transaction, so the job resumes from the last completed chunk if interrupted.

`compress_after_refresh` is a JSONB key on the refresh policy job’s `config` and defaults to `false`. Set it with [`alter_job`](/docs/reference/timescaledb/jobs-automation/alter_job/index.md):

```
SELECT alter_job(<job_id>,
    config => jsonb_set(
        (SELECT config FROM _timescaledb_catalog.bgw_job WHERE id = <job_id>),
        '{compress_after_refresh}', 'true'));
```

You must enable hypercore on the continuous aggregate first. Otherwise, TimescaleDB skips the conversion.
