Skip to content

Unlimited seats on Netlify Pro for $20/month → Learn more 👥

Migrations

Migrations are a way to manage and version changes to your database schema. To ensure that the state of the database matches the exact shape that your application expects, you can define that shape in code and co-locate it with the rest of the application.

This is a crucial but often dreaded aspect of operating a database, because a defective migration has the potential to take down your entire application and even cause permanent data loss.

To help with this, Netlify Database offers a built-in database migration system that automatically tracks and applies migrations for you at the right point in your development cycle.

Migrations are defined in a netlify/database/migrations directory in your project. There are two supported formats:

  • SQL files: each migration is a single SQL file in the migrations directory

    netlify/database/migrations/
    ├── 20260301143000_create_users.sql
    ├── 20260318091500_add_posts.sql
    └── 20260425103000_create_comments.sql
  • Subdirectories: each migration lives in its own subdirectory containing a migration.sql file

    netlify/database/migrations/
    ├── 20260301143000_create_users/
    │ └── migration.sql
    ├── 20260318091500_add_posts/
    │ └── migration.sql
    └── 20260425103000_create_comments/
    └── migration.sql

In both cases, the naming pattern must match <number>_<slug>, where:

  • number is any sequence of digits that defines the relative order of migrations; this is typically a sequential number (e.g. 0001, 0002, etc.) or a Unix timestamp
  • slug is a string containing only lowercase letters, numbers, hyphens, and underscores, typically used to describe the purpose of the migration

Note that migrations are sorted lexicographically and applied in order, which means using Unix timestamps ensures they run in the order they were created.

Netlify will automatically apply your migrations at the right point in the deploy lifecycle:

  • On production deploys, migrations are applied immediately before the deploy is published; a failure when applying the migration will block the deploy from being published
  • On deploy previews, migrations are applied on every new deploy, immediately before it becomes available; a failure when applying the migration will fail the deploy

Imagine your application has a users and posts table, which you had previously defined in the 20260301143000_create_users and 20260318091500_add_posts migrations, respectively.

Now you want to create a table for comments, so you add 20260425103000_create_comments.sql.

netlify/database/migrations/
├── 20260301143000_create_users.sql
├── 20260318091500_add_posts.sql
└── 20260425103000_create_comments.sql

The new migration file describes the full schema of the new table.

netlify/database/migrations/20260425103000_create_comments.sql
CREATE TABLE comments (
id SERIAL PRIMARY KEY,
post_id INTEGER NOT NULL REFERENCES posts(id),
author_id INTEGER NOT NULL REFERENCES users(id),
body TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);

When you open a pull request with this change, Netlify creates a deploy preview and immediately applies the migration to the preview’s database branch. You can verify that the new table works with your application code, test queries against it, and confirm that nothing is broken — all on an isolated copy of your production data.

Once you merge the pull request and a new production deploy is created, one of two things will happen:

  • If auto publishing is enabled, the migration is applied and, if successful, the new deploy is published
  • If not, we’ll wait for you to manually publish the new deploy before we apply the migration

Netlify Database’s native migration system has been designed to offer a seamless integration with the Netlify platform, handling all the complexity of applying migrations at the right time so you can focus on building.

While it is the recommended solution for handling migrations, it is completely optional. You have full access to the database connection details, so you can choose to use your own system for managing and applying migrations.

If you do that, there are some things you should keep in mind:

  • If you want to test a migration on a deploy preview, you are responsible for applying it to the deploy preview’s database branch; you can do this as part of your build command
  • You are responsible for applying migrations to the production database; there is currently no platform hook that lets you run arbitrary logic when a deploy is published, so we recommend an out-of-band process that applies a backwards-compatible migration before you publish the deploy

Because Netlify Database applies migrations at the right point in the deploy lifecycle — just before the new version of your code goes live — the risk of drift between your application code and your database schema is heavily reduced. The window during which the old code is running against the new schema is minimized as much as possible.

Still, as a good practice, we recommend that you always write backwards-compatible migrations. A migration that introduces a breaking change, such as renaming or dropping a column, can cause errors during the brief transition between the old and new versions of your application.

For breaking changes, we recommend the expand and contract pattern. Instead of modifying a structure in place, you:

  1. Expand: Add the new structure (e.g. a new column) alongside the old one, writing to both
  2. Migrate: Move existing data to the new structure
  3. Contract: Once all application code has been updated to use the new structure, remove the old one in a subsequent migration

Non-breaking changes, such as adding a new table or a new nullable column, can safely be applied in a single migration.