Skip to main content

Time-Series Superpowers, Managed: TimescaleDB on FoundryDB

· 5 min read
FoundryDB Team
Engineering @ FoundryDB

Time-series data has a way of sneaking up on you. It starts as one metrics table, then it is device readings, then it is every event your product emits, and one morning that table is the biggest thing in your database and every dashboard query is slow. TimescaleDB is the classic answer inside PostgreSQL: turn the table into a hypertable, roll it up into continuous aggregates, and age it out with retention and compression. The catch is that all of that has always meant writing and babysitting the SQL yourself. Now it does not. Managed TimescaleDB is live on FoundryDB.

Same Postgres, time-series superpowers

This is not a new engine to learn or a new place to put your data. It is your existing FoundryDB PostgreSQL service, with the timescaledb extension enabled, plus a managed control surface over the TimescaleDB features that matter most in production. Turn the extension on at creation time:

curl -u "$USER:$PASS" -X POST \
https://api.foundrydb.com/managed-services \
-H "Content-Type: application/json" \
-d '{
"name": "metrics-db",
"database_type": "postgresql",
"version": "17",
"plan_name": "tier-2",
"zone": "se-sto1",
"storage_size_gb": 50,
"storage_tier": "maxiops",
"extensions": ["timescaledb"]
}'

From there, four things you used to reach for a psql prompt to do are now single API calls.

Hypertables. Point at an existing table and a time column, pick a chunk interval, and the platform partitions it into a hypertable so writes and time-range queries stay fast as the table grows.

curl -u "$USER:$PASS" -X POST \
https://api.foundrydb.com/managed-services/$SERVICE_ID/timescaledb/hypertables \
-H "Content-Type: application/json" \
-d '{"table":"conditions","time_column":"time","chunk_time_interval":"1 day"}'

Continuous aggregates. Define a rollup once and let TimescaleDB keep it current. Create the aggregate from a standard SELECT, then attach an automatic refresh policy so the hourly (or daily, or per-minute) view stays fresh without a cron job you own.

curl -u "$USER:$PASS" -X POST \
https://api.foundrydb.com/managed-services/$SERVICE_ID/timescaledb/continuous-aggregates \
-H "Content-Type: application/json" \
-d '{
"view_name":"conditions_hourly",
"query":"SELECT time_bucket('"'"'1 hour'"'"', time) AS bucket, avg(temperature) AS avg_temp FROM conditions GROUP BY bucket"
}'

Retention policies. Say how long raw data should live and old chunks age out on their own, so a firehose table does not quietly become your storage bill.

curl -u "$USER:$PASS" -X POST \
https://api.foundrydb.com/managed-services/$SERVICE_ID/timescaledb/retention-policies \
-H "Content-Type: application/json" \
-d '{"hypertable":"conditions","drop_after":"30 days"}'

Compression policies. Enable columnar compression on a hypertable, optionally segmenting by a column like device_id, then set a policy to compress chunks once they are past their hot window. Recent data stays fast to write, older data gets small.

curl -u "$USER:$PASS" -X POST \
https://api.foundrydb.com/managed-services/$SERVICE_ID/timescaledb/compression-policies \
-H "Content-Type: application/json" \
-d '{"hypertable":"conditions","compress_after":"7 days"}'

Built to be safe, not just convenient

Every one of these calls composes its SQL on the FoundryDB control plane from validated, quoted inputs, then brokers it to your service's primary as a single managed operation that runs with the right privileges. Table, view, and column names are quoted as identifiers so a name can never break out of its quoting; interval and offset arguments (drop_after, compress_after, refresh windows, chunk intervals) only ever appear inside quoted SQL literals; and a continuous-aggregate definition is validated as one SELECT statement, so nobody can smuggle a second statement in behind it.

The operations are also honest about their preconditions. If a service is not PostgreSQL, or the timescaledb extension is not actually installed in the target database, the call is rejected with a clear error. There is no silent fallback and no half-applied change.

Calls are asynchronous: a mutating or list request returns a task id, and you poll one operation endpoint for the result. That keeps a slow policy build or a large hypertable conversion from blocking your request.

Managed TimescaleDB is available through the FoundryDB API today, with the full request and response reference in the PostgreSQL docs. A dedicated console surface for hypertables, aggregates, and policies is landing in the dashboard alongside it.

Also in this release: reliability improvements across the platform

Alongside TimescaleDB, this cycle carried a broad round of reliability and correctness work across all seven engines. A few of the themes:

  • Failover that stays on the private path. Valkey failover coordination now routes over the private cluster network, so a promotion decision is made on the same trusted path the rest of the cluster uses.
  • Backups that tell the truth. Backup jobs now fail loudly when something is wrong instead of ever reporting success on an empty result. A backup that says it worked, worked.
  • Connection tests that fail fast. Reachability and connection checks now give up quickly on an unreachable target instead of hanging, so you get a clear answer sooner.
  • APIs that return the right thing. Dozens of endpoints across the platform were hardened to return correct validation errors and not-found responses instead of generic failures, which makes the API easier to build against and easier to trust.

None of this changes how you use FoundryDB. It just means more of the platform behaves the way you already expected it to, in the edge cases.

What's next

VPC peering and cross-zone high availability are already generally available, so a TimescaleDB service can span zones today. Next up on the PostgreSQL side is Patroni-based failover for sub-minute primary promotion, which is in active development. We will have more to say on it soon.

Enable timescaledb on a PostgreSQL service, create a hypertable, and let the policies do the aging for you. Your time-series data stays in the Postgres you already run, in your region, and it finally scales without a maintenance job you have to own.