DevStride uses Neon for PostgreSQL hosting, with Drizzle ORM for schema management and migrations. Every developer gets isolated database branches — like git branches, but for your database.
Neon provides instant, copy-on-write database branches:
main (staging data)
├── dev-phil-local ← Phil's local dev branch (stable, branch-independent)
├── dev-phil-feature-auth ← Phil's cloud deploy branch (created by ds deploy up)
├── dev-sarah-local ← Sarah's local dev branch
└── dev-ci-pr-142 ← CI/CD ephemeral branch
main contains the latest staging data. All new branches fork from it.dev-{developer}-local) are used for local development. One per developer, stable across git branch switches.dev-{developer}-{branch}) are created by ds deploy up for isolated cloud testing. Each cloud stage gets its own separate database branch.Before running migrations or resets, it's handy to confirm exactly which database branches your environment is pointing to:
ds db current
This resolves your DB_CONNECTION_STRING and SOURCE_DB_CONNECTION_STRING to human-readable Neon project and branch names:
TARGET DB (DB_CONNECTION_STRING)
Project: devstride-staging
Branch: dev-phil-local
Host: ep-xxx.us-east-1.aws.neon.tech
SOURCE DB (SOURCE_DB_CONNECTION_STRING)
Project: devstride-prod-replica
Branch: main
Host: ep-yyy.us-east-1.aws.neon.tech
ds db migrate
Applies all pending Drizzle ORM migrations to your database. Migrations are idempotent — already-applied migrations are skipped. Shows an interactive Neon branch picker so you can confirm (or change) the target branch before running.
Options:
| Flag | Description |
|---|---|
--target <stage> | Target a specific stage (default: your current DEVSTRIDE_STAGE) |
--db <conn> | Direct connection string — bypasses the interactive picker |
When you modify a database schema:
backend/src/modules/notification/infrastructure/persistence/notification.sql-entity.tscd backend && pnpm generate-sql
backend/drizzle/.ds db migrate
ds local run backend
Neon branches are automatically provisioned by the tooling for standard workflows. You can also manage branches manually using the commands below.
ds setup creates your local branch (dev-{developer}-local) from main and writes the connection string to .envds deploy up (CI) creates a separate branch for each cloud stage (dev-{developer}-{branch}) and stores credentials in Secrets Managerds deploy down tears down the cloud branch along with all other cloud stage resourcesYour local branch (dev-{developer}-local) is independent from cloud branches. Running ds db migrate locally applies migrations to your local branch. Cloud deployments run their own migrations against their own branches.
ds db create-branch [name]
Creates a new Neon database branch from main and updates DB_CONNECTION_STRING in .env. If a branch with that name already exists, switches .env to point to it. Prompts for a name if not provided.
Restart the backend after switching branches.
ds db delete-branch [name]
Deletes a Neon database branch. The main branch is always protected. Shows an interactive picker if no name is provided. Warns if .env still points to the deleted branch.
ds db list-projects
Shows a formatted table of all Neon projects accessible with your API key — including project name, region, project ID, and creation date.
ds db set target-db
Opens an interactive Neon branch picker across all your projects and writes the selected branch's connection URI to DB_CONNECTION_STRING in .env. Use this to point your local backend at a different branch without manually editing .env.
Restart your backend after switching.
ds db set source-db
Same as set target-db, but writes to SOURCE_DB_CONNECTION_STRING. This is the database that ds db reset reads from when seeding data.
ds db reset
Performs a destructive full reset of your database. This is a complete wipe-and-rebuild at the SQL level — not a Neon branch restore.
What happens:
public schema entirely (DROP SCHEMA public CASCADE)SOURCE_DB_CONNECTION_STRING into your databaseRequirements:
SOURCE_DB_CONNECTION_STRING must be set in your .env (points to the data source to seed from)ds db set source-db to configure this interactively if it's not already setOptions:
| Flag | Description |
|---|---|
--target <stage> | Target a specific stage (default: your current DEVSTRIDE_STAGE) |
-o, --organization <id> | Source organization ID to copy |
--source-db <conn> | Override SOURCE_DB_CONNECTION_STRING |
--target-db <conn> | Override DB_CONNECTION_STRING |
When to use:
ds db reset is blocked on dev and prod. It requires explicit confirmation before executing. Your connection string does not change — only the data inside the database is replaced.ds db refresh-staging
This is an admin operation that refreshes the main Neon branch with production data:
main branchOptions:
| Flag | Description |
|---|---|
-o, --organization <id> | Organization ID to copy (default: demo organization) |
Use this when staging data has drifted too far from production, or when you need realistic data for testing.
Here's how database branches fit into the development lifecycle:
| Phase | Command | What Happens |
|---|---|---|
| Setup | ds setup | Creates your Neon branch from main automatically |
| Check current db | ds db current | Shows which Neon branches are active |
| Schema change | pnpm generate-sql then ds db migrate | Generates and applies migration |
| Full reset | ds db reset | SQL drop + migrate + seed from source org |
| Switch branch | ds db set target-db | Interactive picker to switch DB_CONNECTION_STRING |
| New branch | ds db create-branch | Fork a new Neon branch from main |
| Delete branch | ds db delete-branch | Remove a stale Neon branch |
| Staging refresh | ds db refresh-staging | Refreshes main with latest prod data |