Build
Moving from Postgres
Bring an existing database over with pg_dump and psql, and check it came over whole.
SoonThese pages describe Chronos Cloud, which opens from the waitlist. Running Chronos yourself? Self-host docs
Before you start
- Make a project (dashboard, or
chronos init) and have itsDATABASE_URL. The project starts empty. - Have
pg_dumpandpsqlof version 16 or later. - Mind the plan’s storage: 512 MB per database on the free plan.
Move it
Dump the schema and data
terminal pg_dump --no-owner --no-privileges --format=plain \ "postgres://user:password@old-host:5432/shop" > shop.sql--no-ownerand--no-privilegesleave out roles and grants: Chronos’s access is by agents and the app role, not Postgres roles.Load it into a world first
the dashboard’s SQL editor create world import_shop;terminal IMPORT=$(echo "$DATABASE_URL" | sed 's#/main?#/import_shop?#')psql "$IMPORT" -v ON_ERROR_STOP=0 -f shop.sql 2>&1 | tee import.loggrep ERROR import.logEach
ERRORline is a statement Chronos refused; the rest runs on. Most are extensions it doesn’t have, or Postgres features it lacks (see SQL). Fix those inshop.sqland load again into a fresh world, until it runs clean.Merge it
the dashboard’s SQL editor diff world import_shop; -- every table and row it bringsmerge world import_shop;Or open the world on the Worlds page, read its changes, and press Merge.
Check it came over
Compare every table’s row count and a checksum of its rows on both sides:
select 'orders' as t, count(*), md5(string_agg(o::text, '|' order by id)) from orders ounion allselect 'customers', count(*), md5(string_agg(c::text, '|' order by id)) from customers c;- Sequences:
select last_value from orders_id_seqon both;pg_dumpwrites thesetvalthat moves them. - Constraints and indexes:
\d ordersin psql on both. - Functions and triggers: call each once in a world and check what it did.
- Your app’s tests: point them at the world before you merge (see Your app).
Switch the app
- Stop writes to the old database, or note the time.
- Dump and load what changed since (or the whole database again into a fresh world, if it’s small).
- Point the app’s
DATABASE_URLat Chronos and deploy. - Keep the old database, read only, until you’re sure.
What differs
| Postgres has | Chronos |
|---|---|
| extensions with C code | built in instead: pgvector, PostGIS points, pgcrypto, uuid-ossp, citext, hstore, ltree, pg_trgm, fuzzystrmatch, unaccent. Others aren’t available |
| roles and grants | agents with rights, and the app role; row-level security works (make the policies again with CREATE POLICY) |
SERIALIZABLE | refused; READ COMMITTED and REPEATABLE READ work |
hash, brin indexes | made as btrees (they find the same rows) |
| text ordered by your locale | by bytes, as COLLATE "C", unless a column has an ICU collation |
ALTER TABLE … RENAME TO in the catalog only | rewrites the table’s rows (about 6.5 s per million): do it in a quiet moment |
replication, tablespaces, pg_hba.conf | not here |
Trying it locally first
The chronos CLI can import a Postgres database into a folder on your machine, with a report of everything that came over, in part, or not at all, before you touch the cloud:
chronos import ./shopdb "postgres://user:password@old-host:5432/shop" --dry-run # the report onlychronos import ./shopdb "postgres://user:password@old-host:5432/shop"chronos serve ./shopdb # psql postgres://127.0.0.1:5433/mainImport as the tables’ owner or a superuser: a role that row-level security limits would see some tables empty, and the importer refuses rather than bringing part of a table.