In 2022–2023 we delivered, through a partner company, the analytical part of a project to optimise government information systems. One open question was whether to store time series (measurements, events, logs) in plain PostgreSQL or in the TimescaleDB extension. Both sides had arguments, but neither had measurements. We built a repeatable test so that the decision had a basis. This article is for architects and technical leads facing a similar choice: what TimescaleDB is in 2026, what PostgreSQL can do on its own, how to design a test the other side will trust, and how to summarise the result for management.
What TimescaleDB is, and what has changed since
TimescaleDB is a PostgreSQL extension, not a separate database. The application keeps using standard SQL, and the extension adds hypertables: what looks like one table is automatically split into time-based chunks underneath. On top of them sit continuous aggregates: materialised summaries refreshed incrementally, so that only the time buckets whose data changed are recalculated, not the whole view. Since version 2.13 they no longer include the newest, not-yet-materialised rows by default. If results need them, real-time aggregation has to be switched on.
The compression we worked with in 2022–2023 is now described in the documentation as hypercore: new data is written to a rowstore and, as it ages, moved to a columnstore built for scans and aggregations. Since version 2.18 the related functions have new names and the old ones are deprecated. The vendor has changed too: in June 2025 Timescale renamed itself Tiger Data, and its cloud service is called Tiger Cloud. The extension kept the name TimescaleDB. Older documents, contracts and documentation will therefore use both the old and the new names for the company and the features.
Licensing: which part is open source
TimescaleDB code is under two licences. The Apache 2 edition (Apache License 2.0) includes hypertables, basic chunk management and the time_bucket function. The Community edition, under the TSL (called the Timescale License in the licence text itself and the Tiger Data License in the editions documentation), adds what usually justifies adopting it: continuous aggregates, the columnstore and compression, data retention policies and the job scheduler. According to the vendor’s documentation, the Community edition can be run free of charge on your own infrastructure for your own purposes. The licence prohibits offering it as a database-as-a-service or otherwise making it available to third parties as a service. The exception is value-added products that are not primarily a database service, add value of a different nature and do not let users change the database schema. An internal application on top of the database is therefore not an issue, whereas for software offered as a service the licence terms need assessing.
As a result, a managed PostgreSQL offering from a provider other than Tiger Data may include only the Apache 2 edition, without the features that decided our test. The active edition is shown by SHOW timescaledb.license. In public procurement, or when operations are outsourced, the licence belongs in the assessment before performance does: a result measured on your own server may not hold on the hosting you eventually get.
Tied to PostgreSQL versions
Each TimescaleDB release supports only certain PostgreSQL major versions. According to the current compatibility table, versions 2.20 to 2.22 supported PostgreSQL 15 to 17, PostgreSQL 18 arrived in 2.23, and from 2.29 PostgreSQL 15 is no longer supported. The extension has to be loaded at server start (shared_preload_libraries) and is updated separately in each database with ALTER EXTENSION. A PostgreSQL upgrade therefore becomes two coordinated steps: first an extension version that supports both the old and the new PostgreSQL, then PostgreSQL itself.
Some releases also bring changes that need intervention. Continuous aggregates created before version 2.7 use an old format that version 2.25 removed, so they must be migrated while still on an earlier release. The vendor also advises against running the extension on PostgreSQL 17.1, 16.5 and 15.9 because of a binary interface change that PostgreSQL reverted in the following minor releases. None of this is a reason to reject the extension, but it is work that belongs in the operating estimate.
What plain PostgreSQL can do
A fair comparison pits TimescaleDB against well-designed PostgreSQL, not against one huge table with a single index. Plain PostgreSQL has several tools for time series:
- Declarative partitioning by time: the planner skips partitions a query does not need, and old data is removed by detaching or dropping a partition, without a bulk DELETE and the VACUUM load that follows.
- pg_partman: an extension that creates new partitions in advance and drops old ones according to a policy. Since version 5 it works only with native declarative partitioning and requires PostgreSQL 14 or later.
- BRIN indexes: for very large tables where the physical row order matches the time of writing. The index is small and lets the scan skip large parts of the table, but without that correlation it loses its point.
- Materialised views: REFRESH recomputes the whole query, because PostgreSQL has no incremental refresh. The CONCURRENTLY variant does not block reads but requires a unique index. The alternative is summary tables filled by your own scheduled job.
Partitioning is not free either: the PostgreSQL documentation warns that too many partitions lengthen query planning and increase memory use. Partition size is therefore worth measuring, just like chunk size in TimescaleDB.
How to design a fair, repeatable test
Our test rested on four pillars. Both sides ran on the same server and the same PostgreSQL version, with TimescaleDB as an extension on top. The data matched production in volume and shape (hundreds of millions of rows, real distribution of times and keys). The queries came from the application and were not synthetic (latest values, daily and monthly aggregations, window searches, bulk writes). Every query ran several times, and we measured both the median and the worst time. For later decisions of this kind we work from this list:
- The question and the criterion before measuring. Write down which decision the test supports and what difference matters to you. Otherwise the criterion gets adjusted to fit the result.
- Representative data. Volume, distribution over time, key skew and data age as in production. If personal data is involved, anonymise it without changing the distribution.
- Real queries with weights. Take the list of queries and their frequency from production, for example from pg_stat_statements, not from an idea of what the application does.
- The same, isolated environment. Same hardware, versions, configuration and indexes. Nothing else runs on the machine during measurement, and the load-generating client must not become the bottleneck itself.
- The same data state. Run VACUUM ANALYZE on both sides after loading. For TimescaleDB, record which chunks are in the columnstore. Measurements before and after compression are two different results.
- Cold and warm cache separately. A first run is not necessarily cold: PostgreSQL buffers or the operating system may already hold the data. Prepare and document the cache state explicitly and measure both cases. The cache can be warmed in advance, for example with the pg_prewarm module.
- Enough repetitions and the right statistics. Longer runs, more repetitions, the median and p95 or p99 instead of an average distorted by a few outliers. Report the worst time separately.
- Concurrency. Besides isolated queries, a mixed load: writes during reads. pgbench can run custom scripts and log the time of every transaction, from which percentiles can be calculated.
- Explanation, not just time. EXPLAIN ANALYZE on the key queries shows whether a difference came from the plan, from skipped time ranges or from the number of blocks read. Because it executes the statement, run writes inside a transaction with ROLLBACK.
- Recorded configuration. Versions, server settings (EXPLAIN with the SETTINGS option lists deviations from the defaults), and the data-generation and measurement scripts kept in a repository so the other side can repeat the test.
What came out, and what decided it
On aggregations over long periods TimescaleDB was markedly faster thanks to time chunking and continuous aggregates. On point queries and short windows the difference was small or none. On bulk writes Timescale was faster but used more space until compression was enabled. After compression the on-disk volume was smaller than in plain PostgreSQL.
In the end the decision rested on operations more than on raw speed. TimescaleDB adds another component that has to be updated and ties you to specific PostgreSQL versions. It was worth it for the part of the system with long-term aggregations, and plain PostgreSQL stayed for the rest. In a similar decision today, the operating costs we count include:
- the licence of the edition you need and its availability on the chosen hosting,
- an upgrade plan for both PostgreSQL and the extension, and time to test each upgrade,
- restore from backup rehearsed at real volume, not merely the existence of a backup,
- monitoring of background jobs (aggregate refresh, moving data to the columnstore, deleting old data),
- the skills of the team that will run the system several years from now,
- the way back: how to get the data into ordinary tables if the extension stops being a good fit.
A one-page summary for management
Management does not need charts from every run. It needs a decision and a reason to trust it. This structure has worked for us, with everything else in the appendix:
- Question: what is being decided, and by when.
- What we measured: data, queries, environment and number of repetitions in a few sentences.
- What came out: results by workload type (long aggregations, point queries, writes, disk space), with median and p95, and no numbers taken out of context.
- Recommendation: what, for which part of the system, and why.
- Costs and risks: licence, upgrades, required skills, vendor dependency.
- What we did not measure, and where to find the appendix with scripts and raw results.
The test has to run on your data and your queries, otherwise you are measuring something other than your system. It has to be repeatable so the other side can verify it. Its outcome also need not be a single winner. In our case the best answer was to split the system by workload type. Speed is only one of the arguments in such a decision, alongside the licence, upgrades and the people who will run the system.