Migrate from Railway
Railway provides managed PostgreSQL databases as part of its application hosting platform. Since Railway runs standard PostgreSQL, migration to DB9 uses the same pg_dump / import workflow as any PostgreSQL migration.
For the general PostgreSQL migration guide, see Migrate from PostgreSQL.
What Changes and What Stays the Same
Section titled “What Changes and What Stays the Same”Stays the same
Section titled “Stays the same”- SQL compatibility — DB9 supports the same DML, DDL, joins, CTEs, window functions, and subqueries you use in Railway PostgreSQL. Most queries work without changes.
- PostgreSQL drivers — Any driver that connects via pgwire (node-postgres, psycopg, pgx, JDBC) works with DB9.
- ORM compatibility — Prisma, Drizzle, SQLAlchemy, TypeORM, Sequelize, Knex, and GORM are tested and supported.
- Data types — Common types (TEXT, INTEGER, BIGINT, BOOLEAN, TIMESTAMPTZ, UUID, JSONB, arrays, vectors) work identically.
Changes
Section titled “Changes”| Area | Railway PostgreSQL | DB9 |
|---|---|---|
| Connection string | postgresql://postgres:pass@host.railway.app:port/railway | postgresql://tenant.role@pg.db9.io:5433/postgres |
| Port | Varies per deployment | 5433 |
| Database name | railway (default) | Always postgres |
| Connection pooling | No built-in pooler | No built-in pooler — use application-side pooling |
| Extensions | Most community extensions available | 9 built-in (http, vector, fs9, pg_cron, embedding, hstore, uuid-ossp, parquet, zhparser) |
| Replication | Logical replication supported | Not supported |
| Table partitioning | Supported | Not supported |
| LISTEN/NOTIFY | Supported | Not supported |
| Deployment coupling | Tight integration with Railway services via $DATABASE_URL | Standalone — connect from any platform |
Review the Compatibility Matrix for the full list of supported and unsupported features.
Prerequisites
Section titled “Prerequisites”- Access to your Railway project and database credentials
- Railway CLI installed (
npm install -g @railway/cli) or connection string from the Railway dashboard pg_dumpinstalled locally (comes with PostgreSQL client tools)- DB9 CLI installed:
curl -fsSL https://db9.ai/install | sh - A DB9 account:
db9 create --name my-appto create your target database
-
Get Your Railway Connection String
Option A: Railway dashboard
Go to your project → PostgreSQL service → Variables tab → copy
DATABASE_URL.Option B: Railway CLI
Terminal railway loginrailway link # Link to your projectrailway variables get DATABASE_URLThe connection string looks like:
postgresql://postgres:password@host.railway.app:12345/railway -
Export from Railway
Use
pg_dumpwith the Railway connection string.Schema and data (plain SQL format)
Terminal pg_dump --no-owner --no-privileges --no-comments \"postgresql://postgres:password@host.railway.app:12345/railway" \> export.sqlSchema only
Terminal pg_dump --schema-only --no-owner --no-privileges \"postgresql://postgres:password@host.railway.app:12345/railway" \> schema.sqlFlags explained:
--no-owner— omitsALTER ... OWNER TOstatements that reference Railway-specific roles--no-privileges— omitsGRANT/REVOKEstatements--no-comments— omitsCOMMENT ONstatements
Use plain SQL format (default). DB9 does not support
pg_restorewith the custom (-Fc) or directory (-Fd) formats — import via SQL text only. -
Clean the Export
The
pg_dumpoutput may contain statements that DB9 does not support. Remove or comment out:CREATE EXTENSIONfor extensions DB9 does not have — DB9 supports 9 built-in extensions. Remove anyCREATE EXTENSIONfor extensions not in:http,uuid-ossp,hstore,fs9,pg_cron,parquet,zhparser,vector,embedding.CREATE PUBLICATION/CREATE SUBSCRIPTION— DB9 does not support logical replication.- Row-level security policies —
CREATE POLICY,ALTER TABLE ... ENABLE ROW LEVEL SECURITY. - Table partitioning —
PARTITION BY,CREATE TABLE ... PARTITION OF.
A quick way to identify issues:
Terminal # Check for unsupported extensionsgrep "CREATE EXTENSION" export.sql# Check for partitioninggrep -i "PARTITION" export.sql# Check for RLSgrep -i "ROW LEVEL SECURITY\|CREATE POLICY" export.sql# Check for replicationgrep -i "PUBLICATION\|SUBSCRIPTION" export.sql -
Create the DB9 Database
Terminal db9 create --name my-app --show-connection-stringThis returns immediately with the connection string and credentials. Save them for your application config.
-
Import into DB9
Option A: CLI import (recommended for most databases)
Terminal db9 db sql my-app -f export.sqlSuitable for databases up to the API import limits (50,000 rows or 16 MB per table).
Option B: Direct psql import (for larger databases)
Terminal psql "$(db9 db status my-app --json | jq -r .connection_string)" -f export.sqlStreams SQL through pgwire without API size limits.
Option C: COPY for bulk data
Terminal # Import schema firstpsql "$(db9 db status my-app --json | jq -r .connection_string)" -f schema.sql# Then stream data directly from Railway into DB9pg_dump --data-only --no-owner \"postgresql://postgres:password@host.railway.app:12345/railway" \| psql "$(db9 db status my-app --json | jq -r .connection_string)"DB9 supports
COPYin CSV and TEXT formats over pgwire. -
Update Your Application
Connection string
Replace the Railway connection string with DB9’s:
Diff DATABASE_URL=postgresql://postgres:password@host.railway.app:12345/railwayDATABASE_URL=postgresql://a1b2c3d4e5f6.admin@pg.db9.io:5433/postgres?sslmode=requireKey differences:
- Username: DB9 uses
{tenant_id}.{role}format (e.g.,a1b2c3d4e5f6.admin) - Port: 5433
- Database: Always
postgres - Host:
pg.db9.io
Railway service variables
If your Railway services reference
$DATABASE_URLas a shared variable, update the variable in each service that connects to the database, or set a new variable pointing to DB9 and update your code to use it.Connection pooling
Railway does not include a built-in connection pooler, so your application likely already handles pooling. Verify your pool settings work with DB9:
TypeScript const pool = new pg.Pool({connectionString: process.env.DATABASE_URL,max: 10,idleTimeoutMillis: 30000,});For ORMs, see the integration guides: Prisma, Drizzle, SQLAlchemy.
- Username: DB9 uses
-
Validate
Check schema
Terminal db9 db dump my-app --ddl-onlyCompare the output with your original schema to confirm all tables, indexes, and constraints were created.
Check row counts
Terminal db9 db sql my-app -q "SELECT count(*) FROM users"db9 db sql my-app -q "SELECT count(*) FROM orders"Compare row counts against the source Railway database.
Run your test suite
Terminal DATABASE_URL="$(db9 db status my-app --json | jq -r .connection_string)" npm testCheck for unsupported features
If your tests fail, check these common differences:
- SERIALIZABLE isolation — DB9 does not support SERIALIZABLE and returns an error. Use REPEATABLE READ or READ COMMITTED instead
- LISTEN/NOTIFY — not supported; use polling or an external message queue
- Advisory locks — available, but coordination is node-local. For strict row-level coordination, use
SELECT ... FOR UPDATE
Rollback Plan
Section titled “Rollback Plan”If you need to revert:
- Your Railway database is unchanged — switch
DATABASE_URLback to the Railway connection string. - If you need to export data created in DB9 back to Railway:
# Export from DB9db9 db dump my-app -o db9-export.sql
# Import to Railwaypsql "postgresql://postgres:password@host.railway.app:12345/railway" \ -f db9-export.sqlThe db9 db dump command outputs plain SQL (up to 50,000 rows or 16 MB per table). For larger databases, use psql to stream individual tables with COPY.
Caveats
Section titled “Caveats”- No zero-downtime migration — DB9 does not support logical replication, so you cannot stream changes from Railway in real time. Plan a maintenance window or accept a brief cutover period.
- Extension gaps — If your Railway database uses extensions not in DB9’s built-in set (e.g.,
PostGIS,pg_trgm,pgcrypto), those features will not be available. Check yourCREATE EXTENSIONstatements. - Dump size limits — The
db9 db sql -fAPI import has limits (50,000 rows, 16 MB per table). For larger databases, use directpsqlconnection for import. - Railway integration loss — Railway’s tight coupling between services (automatic
DATABASE_URLinjection, private networking) will not apply to DB9. Update each service’s environment variables manually.
Next Pages
Section titled “Next Pages”- Compatibility Matrix — full list of supported and unsupported PostgreSQL features
- Connect — connection string format and authentication options
- Migrate from PostgreSQL — general PostgreSQL migration path
- Production Checklist — deployment readiness