---
title: Understand the data lifecycle | Tiger Data Docs
description: Learn how to manage time-series data from ingestion to deletion using hypertables, continuous aggregates, tiered storage, and retention policies
---

Time-series data is relentless. It grows at an ever-increasing rate and quickly becomes expensive and unwieldy to store and query. Managing your time-series data across its entire lifecycle is essential to building high-performance, cost-effective applications.

TimescaleDB, a time-series database built on PostgreSQL, provides purpose-built features for every stage of the data lifecycle, from the moment data is ingested to when it is archived or dropped. These features work together so you can maintain query performance, control storage costs, and automate routine maintenance — without building custom pipelines or relying on external tools.

For definitions of all terms used in this guide, see the [glossary](/docs/learn/glossary/index.md).

## The five phases

The data lifecycle describes the journey your data takes as it ages. Each phase maps to a set of TimescaleDB features that help you manage that stage efficiently:

| Phase                            | What happens                                    | TimescaleDB features                                                                                                                                                         |
| -------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **1. Ingest and store**          | Data arrives and is written to disk             | [Hypertables](/docs/learn/hypertables/understand-hypertables/index.md), [chunks](/docs/learn/chunks/understanding-chunks/index.md)                                           |
| **2. Query recent data**         | Applications read and analyze fresh data        | SQL, [`time_bucket`](/docs/reference/timescaledb/hyperfunctions/time-series-utilities/time_bucket/index.md), [indexes](/docs/learn/hypertables/hypertable-indexes/index.md)  |
| **3. Create aggregated rollups** | Summarize data at coarser intervals             | [Continuous aggregates](/docs/learn/continuous-aggregates/index.md), [downsampling](/docs/build/data-management/example-downsample-and-compress/index.md)                    |
| **4. Compress and archive**      | Compress and move aging data to cheaper storage | [Columnstore](/docs/learn/columnar-storage/compression-methods/index.md), [tiered storage](/docs/learn/data-lifecycle/storage/about-storage-tiers/index.md)                  |
| **5. Drop old data**             | Remove data that is no longer valuable          | [Retention policies](/docs/learn/data-lifecycle/data-retention/about-data-retention/index.md), [`drop_chunks`](/docs/reference/timescaledb/hypertables/drop_chunks/index.md) |

## Phase 1: ingest and store data efficiently

When it comes to time-series data, storing data as quickly and as efficiently as possible is the foundation of everything else. TimescaleDB achieves this through [hypertables](/docs/learn/hypertables/understand-hypertables/index.md), PostgreSQL tables that are automatically partitioned by time into smaller tables called [chunks](/docs/learn/chunks/understanding-chunks/index.md). Each chunk holds data for a specific time range, such as one week.

Because only recent chunks are in memory, ingest throughput stays high even as overall data volume grows. You interact with hypertables using standard SQL — there is no new query language to learn.

Key considerations at this stage:

- **Choose the right chunk interval.** The default is 7 days. Aim for each chunk to be about 25% of available memory. See [sizing hypertable chunks](/docs/learn/hypertables/sizing-hypertable-chunks/index.md).
- **Plan for columnstore conversion.** As chunks age past their “hot” query window, you can convert them to the [columnstore](/docs/learn/columnar-storage/compression-methods/index.md) for significant storage savings. See [Phase 4](#phase-4-compress-and-archive-older-data).

## Phase 2: query recent data

Once data is stored, you need to query it efficiently. TimescaleDB extends the PostgreSQL query planner with time-series-aware optimizations. Queries on recent data benefit from chunk exclusion, an optimization where the planner automatically skips any chunks that fall outside your query’s time range.

For time-series analysis, the [`time_bucket`](/docs/reference/timescaledb/hyperfunctions/time-series-utilities/time_bucket/index.md) function is a TimescaleDB SQL function that groups rows into fixed time intervals (1 minute, 1 hour, 1 day), making it easy to compute aggregates over time windows:

```
SELECT
  time_bucket('1 hour', time) AS bucket,
  device_id,
  avg(temperature) AS avg_temp
FROM conditions
WHERE time > now() - INTERVAL '7 days'
GROUP BY bucket, device_id
ORDER BY bucket DESC;
```

As your dataset grows and queries over longer time ranges slow down, it is time to move to the next phase.

## Phase 3: create aggregated rollups

As data ages, individual data points often matter less than statistical summaries. [Continuous aggregates](/docs/learn/continuous-aggregates/index.md) solve this. A continuous aggregate is a materialized view that TimescaleDB keeps up to date automatically — it pre-computes and stores the results of an aggregate query (such as averages or counts) and incrementally refreshes only the time buckets where underlying data changed, not the entire view.

Unlike standard PostgreSQL materialized views that recompute everything on each refresh, continuous aggregates are efficient even over very large datasets.

```
CREATE MATERIALIZED VIEW conditions_daily
WITH (timescaledb.continuous) AS
SELECT
  time_bucket('1 day', time) AS day,
  device_id,
  avg(temperature) AS avg_temp,
  min(temperature) AS min_temp,
  max(temperature) AS max_temp
FROM conditions
GROUP BY day, device_id;


SELECT add_continuous_aggregate_policy('conditions_daily',
  start_offset => INTERVAL '7 days',
  end_offset => INTERVAL '1 day',
  schedule_interval => INTERVAL '1 day');
```

Continuous aggregates are stored as hypertables themselves, so they benefit from all the same features — columnstore conversion, tiered storage, and retention policies.

You can also create [hierarchical continuous aggregates](/docs/learn/continuous-aggregates/hierarchical-continuous-aggregates/index.md), where one continuous aggregate reads from another instead of from raw data, to build multi-resolution rollup pipelines (for example, hourly to daily to monthly).

## Phase 4: compress and archive older data

As chunks age past their “hot” query window, you can dramatically reduce storage costs in two ways: convert chunks to the columnstore for compression, and move them to cheaper storage tiers.

### Convert to the columnstore

The [columnstore](/docs/learn/columnar-storage/compression-methods/index.md) is a columnar storage format that compresses your data. Converting older chunks to the columnstore can reduce storage by up to 98% while improving analytical query performance.

Use a [columnstore policy](/docs/reference/timescaledb/hypercore/add_columnstore_policy/index.md) to automatically convert chunks after a set interval:

```
SELECT add_columnstore_policy('conditions', after => INTERVAL '7 days');
```

Once a chunk is in the columnstore, it still supports inserts and updates — [hypercore](/docs/learn/columnar-storage/understand-hypercore/index.md), the underlying storage engine, handles this transparently.

### Tier to low-cost storage

Even with the columnstore and continuous aggregates, there are cases where you need access to raw data for long periods — for compliance, model training, or historical analysis. Rather than paying for high-performance storage you rarely query, you can move older chunks to cheaper storage.

#### On Tiger Cloud

[Tiered storage](/docs/learn/data-lifecycle/storage/about-storage-tiers/index.md) is a Tiger Cloud feature that automatically moves older chunks from high-performance storage to a low-cost object storage tier backed by S3 and Azure Blob. Data is stored in Apache Parquet format with automatic chunk, row group, and column pruning for efficient queries. You set a policy and Tiger Cloud handles the rest:

```
SELECT add_tiering_policy('conditions', INTERVAL '6 months');
```

Tiered data remains queryable via standard SQL — no separate query path or external pipeline required.

#### On self-hosted TimescaleDB

Use PostgreSQL [tablespaces](https://www.postgresql.org/docs/current/manage-ag-tablespaces.html) with the [`move_chunk`](/docs/reference/timescaledb/hypertables/move_chunk/index.md) function to relocate chunks to slower, cheaper disks. You can automate this with a [custom job](/docs/build/data-management/example-tiered-storage/index.md).

## Phase 5: drop old data

At some point, raw data is no longer valuable. Keeping it around slows down queries, inflates storage costs, and adds maintenance overhead. [Retention policies](/docs/learn/data-lifecycle/data-retention/about-data-retention/index.md), scheduled rules that automatically drop chunks older than a threshold you define, automate this process.

```
SELECT add_retention_policy('conditions', INTERVAL '12 months');
```

Because TimescaleDB drops entire chunks rather than deleting rows one by one, retention is nearly instantaneous and avoids the performance overhead of `DELETE` + `VACUUM`.

Important

If you use continuous aggregates, make sure your retention policy interval is longer than the continuous aggregate refresh window. Otherwise, the refresh sees the deleted raw data and removes the aggregate too. For details, see [data retention with continuous aggregates](/docs/learn/data-lifecycle/data-retention/data-retention-with-continuous-aggregates/index.md).

## Putting it all together

A complete lifecycle strategy combines multiple phases. Here is an example configuration for a `conditions` hypertable that stores device telemetry:

```
-- Phase 1: Create the hypertable
SELECT create_hypertable('conditions', by_range('time'));


-- Phase 3: Create a daily rollup
CREATE MATERIALIZED VIEW conditions_daily
WITH (timescaledb.continuous) AS
SELECT time_bucket('1 day', time) AS day, device_id,
       avg(temperature), min(temperature), max(temperature)
FROM conditions
GROUP BY day, device_id;


SELECT add_continuous_aggregate_policy('conditions_daily',
  start_offset => INTERVAL '7 days',
  end_offset => INTERVAL '1 day',
  schedule_interval => INTERVAL '1 day');


-- Phase 4a: Convert to columnstore after 7 days
SELECT add_columnstore_policy('conditions', after => INTERVAL '7 days');


-- Phase 4b: Tier data to low-cost storage after 3 months (Tiger Cloud)
SELECT add_tiering_policy('conditions', INTERVAL '3 months');


-- Phase 5: Drop raw data after 12 months
SELECT add_retention_policy('conditions', INTERVAL '12 months');
```

With this configuration:

- Raw data is converted to the columnstore after 7 days, reducing storage by up to 98%
- Daily summaries are always available via the continuous aggregate
- After 3 months, raw chunks move to low-cost object storage
- After 12 months, raw chunks are dropped entirely
- The daily continuous aggregate retains its data independently of the raw data

All of this runs automatically via scheduled jobs — no cron, no external scripts, no manual intervention.

## Automate and customize

Every lifecycle feature supports scheduled automation through the TimescaleDB [job scheduler](/docs/build/data-management/about-automation/index.md). A job is a user-defined or built-in stored procedure that TimescaleDB runs on a schedule you configure — policies like retention, columnstore conversion, and continuous aggregate refresh are all implemented as jobs under the hood.

If the built-in policies don’t cover your use case, you can create [custom jobs](/docs/build/data-management/create-and-manage-jobs/index.md). Common examples include:

- [Generic retention across all hypertables](/docs/build/data-management/example-generic-retention/index.md)
- [Automated tablespace management](/docs/build/data-management/example-tiered-storage/index.md)
- [Downsampling and converting to columnstore in one step](/docs/build/data-management/example-downsample-and-compress/index.md)

## Get hands on

[Your first hypertable](/docs/build/how-to/your-first-hypertable/index.md)

[Create a hypertable, insert data, and run your first queries.](/docs/build/how-to/your-first-hypertable/index.md)

[Create a continuous aggregate](/docs/build/continuous-aggregates/create-a-continuous-aggregate/index.md)

[Build pre-computed rollups that refresh automatically.](/docs/build/continuous-aggregates/create-a-continuous-aggregate/index.md)

[Set up hypercore](/docs/build/columnar-storage/setup-hypercore/index.md)

[Enable columnstore compression on your hypertables.](/docs/build/columnar-storage/setup-hypercore/index.md)

[Manage storage and tiering](/docs/build/data-management/storage/manage-storage/index.md)

[Move older data to low-cost object storage.](/docs/build/data-management/storage/manage-storage/index.md)

[Create a retention policy](/docs/build/data-management/data-retention/create-a-retention-policy/index.md)

[Automate dropping chunks past a defined age.](/docs/build/data-management/data-retention/create-a-retention-policy/index.md)

[Create and manage custom jobs](/docs/build/data-management/create-and-manage-jobs/index.md)

[Build your own scheduled automation with the job scheduler.](/docs/build/data-management/create-and-manage-jobs/index.md)

## Learn more

### By lifecycle phase

- **Ingest:** [Understand hypertables](/docs/learn/hypertables/understand-hypertables/index.md) | [Size chunks](/docs/learn/hypertables/sizing-hypertable-chunks/index.md)
- **Query:** [Understand time buckets](/docs/learn/data-lifecycle/time-buckets/about-time-buckets/index.md) | [Hypertable indexes](/docs/learn/hypertables/hypertable-indexes/index.md)
- **Rollup:** [Understand continuous aggregates](/docs/learn/continuous-aggregates/index.md) | [Hierarchical continuous aggregates](/docs/learn/continuous-aggregates/hierarchical-continuous-aggregates/index.md)
- **Compress and archive:** [Understand hypercore](/docs/learn/columnar-storage/understand-hypercore/index.md) | [Columnstore methods](/docs/learn/columnar-storage/compression-methods/index.md) | [Understand tiered storage](/docs/learn/data-lifecycle/storage/about-storage-tiers/index.md)
- **Drop:** [Understand data retention](/docs/learn/data-lifecycle/data-retention/about-data-retention/index.md) | [Retention with continuous aggregates](/docs/learn/data-lifecycle/data-retention/data-retention-with-continuous-aggregates/index.md)

### Automation and reference

- [About automation](/docs/build/data-management/about-automation/index.md)
- [`add_columnstore_policy()`](/docs/reference/timescaledb/hypercore/add_columnstore_policy/index.md)
- [`add_job()` reference](/docs/reference/timescaledb/jobs-automation/add_job/index.md)
