Time-series databases are purpose-built for storing and querying data points indexed by time. Whether you’re collecting server metrics, IoT sensor readings, application performance data, or financial tick data, a specialized time-series database will outperform a general-purpose database for these workloads.

M3DB, QuestDB, and TimescaleDB represent three distinct approaches to time-series data storage. M3DB is a distributed database designed as a Prometheus long-term store, QuestDB is a high-performance columnar database optimized for fast ingestion and SQL queries, and TimescaleDB extends PostgreSQL with time-series capabilities.

In this guide, we compare all three databases with Docker Compose configurations, query examples, and deployment instructions.

What Are Time-Series Databases?

Time-series databases (TSDBs) optimize for workloads where data is:

  • Time-ordered — every record has a timestamp, and queries are typically time-range based
  • Append-heavy — new data is constantly written, with rare updates or deletes
  • Aggregation-friendly — queries often compute averages, sums, percentiles over time windows
  • High-cardinality — many unique tag combinations (e.g., per-host, per-service metrics)

Unlike relational databases, TSDBs use specialized storage engines, compression algorithms, and indexing strategies to handle billions of data points efficiently.

M3DB

M3DB (4,890+ stars) is a distributed time-series database created by Uber and now part of the CNCF landscape. It was specifically designed as a long-term storage backend for Prometheus, with horizontal scaling, replication, and multi-tenant support.

Key Features

  • Prometheus remote write/read — drop-in replacement for Prometheus long-term storage
  • Horizontal scalability — add nodes to increase capacity and throughput
  • Built-in replication — configurable replication factor for fault tolerance
  • Multi-tenancy — isolate data by namespace with per-namespace retention policies
  • Graphite compatibility — ingest and query Graphite-format metrics

Docker Compose Setup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
version: "3.8"
services:
  m3db:
    image: quay.io/m3db/m3dbnode:latest
    ports:
      - "7201:7201"
      - "7203:7203"
      - "9003:9003"
    volumes:
      - m3db_data:/var/lib/m3db
    environment:
      - GOMAXPROCS=4
    command: >
      -f /etc/m3db/m3dbnode-config.yaml
    restart: unless-stopped

  m3coordinator:
    image: quay.io/m3db/m3coordinator:latest
    ports:
      - "7201:7201"
      - "7202:7202"
      - "7203:7203"
    depends_on:
      - m3db
    command: >
      -f /etc/m3db/m3coordinator-config.yaml
    restart: unless-stopped

  m3query:
    image: quay.io/m3db/m3query:latest
    ports:
      - "7204:7204"
    depends_on:
      - m3coordinator
    restart: unless-stopped

volumes:
  m3db_data:

M3DB initialization (run once):

1
2
3
4
5
curl -X POST http://localhost:7201/api/v1/database/create -d '{
  "type": "local",
  "namespaceName": "default",
  "retentionTime": "48h"
}'

Query Examples

PromQL query via M3Query:

1
GET http://localhost:7204/api/v1/query_range?query=up&start=2026-01-01T00:00:00Z&end=2026-01-02T00:00:00Z&step=60s

Pros and Cons

ProsCons
Native Prometheus integrationComplex deployment with multiple components
Horizontal scalabilitySteep operational learning curve
Built-in replication and fault toleranceSmaller community than TimescaleDB
Multi-tenant with namespace isolationLimited SQL query support

QuestDB

QuestDB (6,200+ stars) is a high-performance, open-source time-series database with SQL support. It uses a custom columnar storage engine optimized for fast ingestion and analytical queries, making it ideal for financial market data, IoT telemetry, and application metrics.

Key Features

  • SQL interface — standard SQL with time-series extensions (SAMPLE BY, LATEST ON)
  • Columnar storage — optimized for analytical queries over large time ranges
  • High ingestion rate — millions of rows per second on modern hardware
  • InfluxDB Line Protocol — compatible with InfluxDB clients and tools
  • PostgreSQL wire protocol — connect with any PostgreSQL-compatible tool

Docker Compose Setup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
version: "3.8"
services:
  questdb:
    image: questdb/questdb:latest
    ports:
      - "9000:9000"   # REST API and Web Console
      - "8812:8812"   # PostgreSQL wire protocol
      - "9009:9009"   # InfluxDB Line Protocol
    volumes:
      - questdb_data:/root/.questdb/db
    environment:
      - QDB_PG_USER=admin
      - QDB_PG_PASSWORD=quest
    restart: unless-stopped

volumes:
  questdb_data:

Query Examples

Create a table and insert data:

1
2
3
4
5
6
7
8
CREATE TABLE sensors (
    id SYMBOL,
    temperature DOUBLE,
    humidity DOUBLE,
    timestamp TIMESTAMP
) TIMESTAMP(timestamp) PARTITION BY DAY;

INSERT INTO sensors VALUES ('sensor-1', 22.5, 65.0, '2026-05-18T10:00:00');

Time-series aggregation:

1
2
3
4
5
6
7
SELECT 
    id,
    avg(temperature),
    max(humidity),
    timestamp
FROM sensors
SAMPLE BY 1h ALIGN TO CALENDAR;

Pros and Cons

ProsCons
Fastest ingestion of the threeNo built-in replication/HA
Standard SQL with TS extensionsYounger project, smaller ecosystem
Web Console for ad-hoc queriesLimited multi-node support
PostgreSQL and InfluxDB compatibleNo native Prometheus integration

TimescaleDB

TimescaleDB (18,000+ stars) extends PostgreSQL with automatic time-based partitioning (hypertables), continuous aggregates, and time-series functions. It gives you full PostgreSQL capabilities — joins, transactions, extensions — plus time-series optimizations.

Key Features

  • Full PostgreSQL compatibility — use any PostgreSQL tool, driver, or extension
  • Hypertables — automatic partitioning by time (and optional space partitioning)
  • Continuous aggregates — pre-computed materialized views that update automatically
  • Compression — columnar compression for historical data, reducing storage by 90%+
  • Time-series functions — time_bucket, interpolate, gapfill, and more

Docker Compose Setup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
version: "3.8"
services:
  timescaledb:
    image: timescale/timescaledb:latest-pg16
    ports:
      - "5432:5432"
    volumes:
      - tsdb_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_DB=metrics
    command: >
      postgres
      -c shared_preload_libraries=timescaledb
      -c max_connections=200
    restart: unless-stopped

volumes:
  tsdb_data:

Query Examples

Create a hypertable:

1
2
3
4
5
6
7
8
CREATE TABLE conditions (
    time TIMESTAMPTZ NOT NULL,
    location TEXT NOT NULL,
    temperature DOUBLE PRECISION,
    humidity DOUBLE PRECISION
);

SELECT create_hypertable('conditions', 'time');

Continuous aggregate:

1
2
3
4
5
6
7
8
9
CREATE MATERIALIZED VIEW conditions_hourly
WITH (timescaledb.continuous) AS
SELECT
    time_bucket('1 hour', time) AS bucket,
    location,
    avg(temperature) AS avg_temp,
    max(humidity) AS max_humidity
FROM conditions
GROUP BY bucket, location;

Time-series query with gap filling:

1
2
3
4
5
6
7
8
SELECT 
    time_bucket('1 day', time) AS day,
    location,
    avg(temperature)
FROM conditions
WHERE time > NOW() - INTERVAL '30 days'
GROUP BY day, location
ORDER BY day;

Pros and Cons

ProsCons
Full PostgreSQL compatibilitySingle-node write scalability limit
Largest ecosystem and communityRequires PostgreSQL knowledge
Continuous aggregatesDistributed edition requires license
Mature compression and retention policiesHeavier resource usage than QuestDB

Comparison Table

FeatureM3DBQuestDBTimescaleDB
GitHub Stars4,890+6,200+18,000+
Query LanguagePromQL, M3QLSQL (TS extensions)SQL (PostgreSQL)
Storage EngineCustom distributedColumnarPostgreSQL heap + BRIN
Horizontal Scaling✅ Native⚠️ Limited⚠️ Enterprise only
Prometheus Integration✅ Native
PostgreSQL Compatible✅ Wire protocol✅ Full
Built-in Replication✅ (via PostgreSQL)
Time-Series FunctionsBasicGood (SAMPLE BY, LATEST ON)Excellent (time_bucket, gapfill)
Continuous Aggregates
Data Compression✅ (columnar)
Web Console✅ Built-inVia pgAdmin/DBeaver
Best ForPrometheus long-term storageHigh-speed ingestion, SQL analyticsGeneral time-series with full SQL

Choosing the Right Time-Series Database

Choose M3DB if: You’re already using Prometheus and need a scalable, distributed long-term storage backend. Its native PromQL support and horizontal scaling make it the natural choice for large-scale metrics infrastructure.

Choose QuestDB if: You need maximum ingestion throughput and want to query time-series data with standard SQL. The columnar storage engine and time-series SQL extensions make it ideal for financial data, IoT telemetry, and log analytics.

Choose TimescaleDB if: You want the full power of PostgreSQL combined with time-series optimizations. The hypertable abstraction, continuous aggregates, and PostgreSQL ecosystem make it the most versatile choice for teams that already use PostgreSQL.

Why Self-Host Your Time-Series Database?

Managed time-series services (Datadog, New Relic, InfluxDB Cloud) charge per metric, per gigabyte, or per query — costs that scale unpredictably as your monitoring needs grow. Self-hosting gives you:

Cost control — store billions of data points on commodity hardware without per-metric fees. TimescaleDB compression alone can reduce storage costs by 90% compared to raw PostgreSQL.

Data retention flexibility — define custom retention policies per metric type. Keep high-resolution data for recent periods and downsampled aggregates for historical analysis, all within the same database.

No vendor lock-in — standard SQL (QuestDB, TimescaleDB) or PromQL (M3DB) means you can migrate between platforms or integrate with any visualization tool without proprietary query languages.

For related monitoring infrastructure, see our Grafana Mimir vs Thanos vs Cortex Prometheus storage guide and our Prometheus alerting comparison.

FAQ

Can M3DB replace Prometheus entirely?

No. M3DB is designed as a long-term storage backend for Prometheus, not a complete replacement. You still need Prometheus (or the M3Coordinator) for metric collection, alerting, and service discovery. M3DB handles the storage and query layer for historical data.

Does QuestDB support real-time streaming ingestion?

Yes. QuestDB supports InfluxDB Line Protocol for real-time data ingestion over UDP or TCP, and a REST API for batch inserts. It can ingest millions of rows per second on modern hardware, making it suitable for high-frequency trading data and IoT sensor streams.

How does TimescaleDB compression work?

TimescaleDB compresses historical data by converting row-based storage to columnar format, applying dictionary encoding and delta encoding. You configure compression policies by time interval (e.g., compress data older than 7 days). Compressed data is typically 10-50x smaller than raw storage.

Can I migrate from InfluxDB to QuestDB or TimescaleDB?

QuestDB supports the InfluxDB Line Protocol, so you can redirect InfluxDB clients directly to QuestDB without code changes. For historical data migration, export InfluxDB data as line protocol or CSV and import into QuestDB or TimescaleDB.

Which database is best for IoT sensor data?

QuestDB is optimized for high-speed ingestion of time-stamped sensor readings with SQL analytics. TimescaleDB is better if you need to join sensor data with relational data (device metadata, location info) using full SQL. M3DB is less suited for IoT unless you’re already in a Prometheus monitoring ecosystem.

How do I back up a self-hosted time-series database?

M3DB has built-in snapshot-based backups to S3-compatible storage. QuestDB supports file-level backups of its data directory. TimescaleDB uses standard PostgreSQL backup tools (pg_dump, pg_basebackup) plus its own continuous archive backup features for point-in-time recovery.