How ChronoTables work
A ChronoTable is a regular PostgreSQL table partitioned by time. It presents a single logical table while storing data in many smaller physical tables — chunks — one per time interval:
metrics (logical table)
├── metrics_20260320_000000 (Mar 20)
├── metrics_20260321_000000 (Mar 21)
├── metrics_20260322_000000 (Mar 22)
├── metrics_20260323_000000 (Mar 23, current)
└── metrics_20260324_000000 (Mar 24, pre-created)
Partitioning by time buys three properties:
- Fast inserts — new rows touch only the current chunk's indexes, not one index spanning the entire history.
- Fast queries — Postgres prunes chunks outside the query's time range, so a one-hour query never scans a year of data.
- Cheap eviction — removing old data is a
DROP TABLEon a chunk, a metadata operation, rather than a row-by-rowDELETE.
Routing and pruning
Postgres declarative RANGE partitioning routes each insert to the chunk whose bounds cover its timestamp, and prunes non-matching chunks when a query filters on time.
A row whose timestamp falls outside every existing chunk is rejected, which is why chunks must be created ahead of the write stream — the role of _ensure_partitions and the Partition Manager job.
Creating a ChronoTable
create_chronotable('metrics', 'time', '1 day') converts an existing table in place (the default chunk interval is 7 days):
The conversion scans the existing data range to decide how many historical chunks to create, then lays down a small rolling window around the present (one past chunk and several future chunks) so writes have somewhere to land immediately. Column definitions are reconstructed from the catalog; because a column DEFAULT is raw SQL that cannot be parameterized, any default containing ;, --, or /* is rejected to prevent injection.
partition_manager keeps that future window provisioned as time advances:
Managing chunks
| Function | Purpose |
|---|---|
show_chunks('metrics') | Lists active chunks with range, status, row count, and size |
set_chunk_interval('metrics', '1 hour') | Changes the interval for future chunks; existing chunks are unchanged |
drop_chunks('metrics', '90 days') | Drops active chunks older than the interval (per-chunk DROP TABLE) |
drop_chronotable('metrics') | Full teardown — RollUps, LVC, CDF shadow, registries, then the partitioned table |
Metadata
Two registry tables track ChronoTable state:
-- Registered ChronoTables
SELECT schema_name, table_name, time_column, chunk_interval, tiering_enabled, sync_enabled
FROM lakets._chronotable_registry;
-- Chunks and their lifecycle status
SELECT chunk_name, range_start, range_end, status, row_count, size_bytes
FROM lakets._chunk_metadata;
-- status is one of: active, tiered, dropped
_chunk_metadata also carries last_write_lsn — the WAL position of each chunk's most recent write, stamped by the tiering write-tracking triggers and used by the durability gate.