Typebase.
Database

Pushing Schema Changes

Apply your schema changes to the database.

Last updated on

After modifying your schema, you need to push the changes to your database so the actual tables reflect your definitions.

Pushing is one of two ways to get a schema change into a database. The other is migrations, where changes are recorded as reviewable SQL files and applied deliberately. Push is the default; everything on this page describes a project that has not opted into migrations.

Dev and prod are separate branches

Typebase provisions two independent Neon branches inside the same project: one for dev and one for prod. Each branch has its own data, so you can iterate on your schema freely in development without risking your production data. Always test schema changes in dev before pushing to prod.

Pushing changes

Push to your dev database:

npx typebase-io-cli db dev push

Push to your prod database:

npx typebase-io-cli db prod push

You don't need to run this manually every time. npx typebase-io-cli deploy dev and npx typebase-io-cli deploy prod automatically push your schema changes as part of the deployment process. So if you're deploying anyway, your database will always be in sync with your schema without any extra steps.

npx typebase-io-cli start does the same for a local run: every time you change something under typebase/db/, it pushes to the database you're running against before it restarts the server, so the server you're talking to always matches the schema you just edited.

That last part stops being true once a project uses migrations. In migrations mode deploy applies your pending migrations instead of pushing, and refuses to deploy at all when your schema files hold changes no migration records.

Environment variables

The first time you push, the CLI provisions a Neon project (and the target branch if it doesn't exist yet) and stores the connection string in your project-root .env:

  • In your project-root .env: under DATABASE_URL for prod and DATABASE_URL_DEV for dev, so both connection strings can coexist in a single local file.

Provider environment variables are synced during npx typebase-io-cli deploy. On the provider, the deployed server always reads DATABASE_URL; each environment (dev, prod) gets its own value.

Destructive changes

If a schema change would destroy existing data (such as dropping a table or removing a column), the CLI will detect this and warn you before proceeding:

⚠ The following changes are destructive:
  - Column "email" will be dropped from table "users"

? Are you sure you want to continue? (y/N)

By default the CLI will not apply a destructive change until you answer that prompt. In production, treat these warnings carefully. Dropped columns and tables cannot be recovered.

Answering the prompt ahead of time

A pipeline has nobody at the keyboard, so each command that pushes takes a flag that answers the prompt in advance:

npx typebase-io-cli db dev push --skip-confirmation
npx typebase-io-cli deploy dev --skip-schema-changes-confirmation
npx typebase-io-cli start --skip-schema-changes-confirmation

The warnings are printed either way, so the log still records what was dropped. Nothing stops it, though, so reach for these only on a pipeline where the schema change has already been reviewed.

Viewing your data in Neon

Every Typebase database lives in a Neon project. You can log in to the Neon console to browse your data visually: inspect tables, run ad-hoc SELECT queries, check indexes, and switch between the dev and prod branches.

Don't edit your schema from the Neon UI. Your typebase/db/schema.ts is the source of truth. If you add a column, rename a table, or change a constraint directly in Neon, the next npx typebase-io-cli db <target> push will detect the drift and try to "correct" it back to what schema.ts describes, which usually means reverting your change, and in some cases failing the push outright.

The Neon UI is fine (and useful) for:

  • Reading data and running queries
  • Debugging a specific row or running a one-off data fix
  • Exploring what the current schema actually looks like on the branch

For anything that changes the schema shape (tables, columns, types, constraints, indexes tied to your schema), edit schema.ts and run npx typebase-io-cli db dev push (or db prod push for production).

When push isn't enough

Push applies a change and leaves no record of it. There is no file to review in a pull request, no history to read, and no way to inspect the SQL before it runs. Anything the diff cannot express — a backfill, a rename it would turn into a drop-and-recreate — has nowhere to live, and two developers changing the schema on separate branches have nothing that notices the divergence.

Migrations exist for exactly those cases. You can adopt them on an existing project without recreating your databases:

npx typebase-io-cli db migrations init

Once a project has a typebase/db/migrations/ folder, the two modes are mutually exclusive: push refuses to run and points at db <target> migrate instead.

On this page