Skip to content

Postgres

SQLite is the zero configuration default, running in WAL mode with a single serialized writer. It comfortably handles small and mid-size teams. The schema is deliberately portable, so moving is a migration rather than a rewrite.

Move when you have a concrete reason: several application nodes, a managed backup story you already trust, or a team large enough that write contention shows up in practice. Do not move because Postgres feels more serious. A single SQLite writer will outrun most teams’ actual message rate.

Terminal window
node dist/index.js migrate-to-postgres postgres://user:pass@host:5432/slick

This copies every table into a freshly migrated, empty Postgres database and prints per-table row counts for verification. It preserves workspace_events sequence values, which is the part that matters: connected clients resume where they left off instead of being forced into a full resync.

Then restart with DATABASE_URL set. The files directory is used as is.

Both dialects use TEXT ULID identifiers and epoch-millisecond integer timestamps, so application behaviour is identical. Two things differ under the hood:

  • Full text search uses a generated tsvector column with a GIN index instead of SQLite’s FTS5.
  • Epoch timestamps are bigint on Postgres, since they overflow integer.

backup remains SQLite only. On Postgres, use pg_dump.