Chronos/DBWaitlist

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 its DATABASE_URL. The project starts empty.
  • Have pg_dump and psql of version 16 or later.
  • Mind the plan’s storage: 512 MB per database on the free plan.

Move it

  1. Dump the schema and data

    terminal
    pg_dump --no-owner --no-privileges --format=plain \  "postgres://user:password@old-host:5432/shop" > shop.sql

    --no-owner and --no-privileges leave out roles and grants: Chronos’s access is by agents and the app role, not Postgres roles.

  2. 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.log

    Each ERROR line 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 in shop.sql and load again into a fresh world, until it runs clean.

  3. 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:

run on Postgres and on Chronos, then compare
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_seq on both; pg_dump writes the setval that moves them.
  • Constraints and indexes: \d orders in 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

  1. Stop writes to the old database, or note the time.
  2. Dump and load what changed since (or the whole database again into a fresh world, if it’s small).
  3. Point the app’s DATABASE_URL at Chronos and deploy.
  4. Keep the old database, read only, until you’re sure.

What differs

Postgres hasChronos
extensions with C codebuilt in instead: pgvector, PostGIS points, pgcrypto, uuid-ossp, citext, hstore, ltree, pg_trgm, fuzzystrmatch, unaccent. Others aren’t available
roles and grantsagents with rights, and the app role; row-level security works (make the policies again with CREATE POLICY)
SERIALIZABLErefused; READ COMMITTED and REPEATABLE READ work
hash, brin indexesmade as btrees (they find the same rows)
text ordered by your localeby bytes, as COLLATE "C", unless a column has an ICU collation
ALTER TABLE … RENAME TO in the catalog onlyrewrites the table’s rows (about 6.5 s per million): do it in a quiet moment
replication, tablespaces, pg_hba.confnot 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:

terminal
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/main

Import 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.

Moving from Postgres · Chronos