Database Migrations

Purpose and Scope

Database migrations are the supported way to move a Cal.diy database from one schema shape to another. The first-party documentation is explicit that database updates should be handled with the Prisma workspace migration commands rather than by only editing the Prisma schema and hoping the database catches up. This matters because Cal.diy is a self-hosted scheduling platform where the operator owns the PostgreSQL database and is responsible for preserving user, booking, credential, and integration data. A migration records the intended transformation as a reproducible step, making the change transparent enough to review and stable enough to repeat across environments.

Sources: apps/docs/content/database-migrations.mdx

This page is for maintainers and self-hosters who modify the codebase, upgrade an instance, or recover from a Prisma migration state mismatch. It explains when to create a migration, how to apply existing migrations, why generated SQL must be reviewed, and how to recover when Prisma reports that a database is not empty. It also places the migration page in the broader documentation flow: the docs navigation lists Database Migrations alongside Installation, Upgrading, and Docker, which signals that schema state is part of normal instance maintenance rather than an isolated developer-only concern.

Sources: apps/docs/content/database-migrations.mdx, apps/docs/content/_meta.ts

Relevant Source Files

  • apps/docs/content/database-migrations.mdx — The primary documentation page for Cal.diy database migration commands, migration creation, Prisma schema-state errors, and local reset guidance.
  • apps/docs/content/_meta.ts — Places database migrations in the main documentation navigation near installation, upgrading, and Docker topics, showing that this is part of the self-hosting lifecycle.
  • apps/docs/content/apps/_meta.ts — Lists integration setup pages that may need app-store configuration and seeding after database and environment changes are in place.
  • apps/docs/content/apps/daily.mdx — Shows an integration setup pattern based on environment variables, which often accompanies database-backed app configuration in a self-hosted instance.
  • apps/docs/content/apps/google.mdx — Documents Google Calendar setup and explicitly instructs operators to repopulate the app store with a database seed command after adding credentials.
  • apps/docs/content/apps/hubspot.mdx — Shows another OAuth integration flow that depends on saved environment variables and callback configuration, reinforcing why database and app setup should be coordinated.

Migration Commands and When to Use Them

The docs name two workspace commands for updating the database: one for migration work and one for deployment-style application of migrations. Use the migration command when you are developing a schema change and need Prisma to create a migration from the current model difference. Use the deploy command when an existing set of migrations needs to be applied to a database as part of an upgrade or release process. The important distinction is intent: creating a migration produces a new reviewed schema transition, while deploying migrations applies already committed transitions to an environment.

Sources: apps/docs/content/database-migrations.mdx

yarn workspace @calcom/prisma db-migrate
yarn workspace @calcom/prisma db-deploy

The repository documentation emphasizes that migrations are safer than direct schema mutation because Prisma cannot always infer how to transform existing production data. If a column disappears from the schema or a relation changes shape, an automatic update path might drop information that the application still needs or that users expect to keep. A migration gives maintainers a concrete artifact to inspect before it touches a real database. Treat the generated migration as a proposal, not as an unquestioned truth, especially when the change affects populated tables or identity, booking, payment, or credential-related models.

Sources: apps/docs/content/database-migrations.mdx

Creating a Migration for a Schema Change

Create a migration whenever your code change modifies the Prisma schema. A schema change and the application code that depends on it should be committed together, because reviewers and deployers need to understand the full behavior change. The docs recommend running the migration command after changing the schema, then giving the migration a short descriptive name. The example name uses a compact domain-action-field style, which is helpful because migration directories are often reviewed months later during upgrades, local recovery, or debugging of a failed deployment.

Sources: apps/docs/content/database-migrations.mdx

yarn workspace @calcom/prisma db-migrate

A practical review loop is to first make the schema edit, then run the migration command, then read the generated output before committing. If Prisma proposes dropping a column, deleting a table, changing a required field, or rewriting a relation, stop and verify that the result is intentional. The docs specifically warn that Prisma may happily drop entire columns of data when it cannot infer a safe transformation. That warning should shape the developer workflow: inspect the generated migration, consider whether data backfill is needed, and only then commit it with the corresponding code.

Sources: apps/docs/content/database-migrations.mdx

Applying Migrations During Upgrades

For normal instance maintenance, applying migrations is part of upgrading Cal.diy. The migration page refers readers back to the upgrade guide and states that the workspace migration or deploy command should be used to update the database. In an operator workflow, that means schema updates should not be treated as a hidden side effect of starting the web application. They are an explicit step in the release process, alongside pulling new code, rebuilding containers or packages, checking environment variables, and restarting services after the database reaches the expected schema state.

Sources: apps/docs/content/database-migrations.mdx, apps/docs/content/_meta.ts

In practice, separate the concerns of creating and applying migrations. A contributor modifying the codebase creates the migration and commits it. A self-hosted operator applying an upgrade runs the deployment-oriented database command against the target database. This separation reduces the chance that a production server accidentally generates a new migration based on local drift. It also makes rollback and troubleshooting clearer because the database can be compared against the committed migration history rather than against whatever schema file happened to be present on disk during a failed startup.

Sources: apps/docs/content/database-migrations.mdx

Recovering from a Non-Empty Database Error

Prisma tracks applied migrations in a database table named for its migration metadata. When that metadata does not match the actual database state, Prisma can raise the error documented as P3005, explaining that the database schema is not empty. The Cal.diy docs describe this as a mismatch between the local migrations database and the actual database. The fix is not to force destructive schema changes. Instead, tell Prisma which migrations have already been applied so its metadata catches up with the real database state.

Sources: apps/docs/content/database-migrations.mdx

Error: P3005
 
The database schema for `localhost:5432` is not empty. Read more about how to baseline an existing production database: https://pris.ly/d/migrate-baseline
yarn prisma migrate resolve --applied migration_name

Run the resolve command once for each migration that should be marked as applied, replacing the placeholder with the exact migration name. This approach is especially important for databases that already contain tables, because Prisma needs a baseline before it can reason about future migrations. The command does not mean every migration is safe for every database; it means you are asserting that the database already reflects that migration. Make that assertion deliberately, ideally after checking the migration history, the existing schema, and the environment you are connected to.

Sources: apps/docs/content/database-migrations.mdx

Resetting Local Prisma Migrate State

The docs also include a local reset technique for a Prisma migrate state that has become confusing during development. It deletes the contents of the migration metadata table and then quickly re-indexes migrations from the local migration directory by resolving each migration as applied. This is recovery guidance for a local database that has drifted from the migration list, not a casual production maintenance shortcut. Deleting migration metadata removes Prisma’s record of what happened, so the safety of the reset depends on knowing that the actual schema already matches the migrations being marked applied.

Sources: apps/docs/content/database-migrations.mdx

DELETE FROM "_prisma_migrations";
# Run the following to easily apply all migrations in the prisma/migrations directory
ls -1a prisma/migrations/ | grep 2021 | xargs -I{} prisma migrate resolve --applied {}

Use the reset flow only when the local environment is disposable or otherwise well understood. Before resetting metadata, confirm that the database connection string points at the intended local PostgreSQL database, not a shared staging or production system. After re-indexing, run the normal migration command again and verify that Prisma no longer sees unexpected drift. If the application has test data that matters, take a backup first. The command sequence is short, but its effect is broad because it rewrites Prisma’s understanding of migration history.

Sources: apps/docs/content/database-migrations.mdx

Coordination with Apps and App-Store Seeding

Database migrations are not the only stateful setup step in Cal.diy. The app documentation shows that integrations are configured through environment variables, OAuth callback URLs, and in some cases app-store repopulation. The Google Calendar guide, for example, instructs operators to add OAuth credentials, set login behavior, and then repopulate the app store by running a database seed command so the integration appears in the app store. This is not a migration command, but it is a database-affecting operational step that should be coordinated with schema readiness.

Sources: apps/docs/content/apps/_meta.ts, apps/docs/content/apps/google.mdx

Daily and HubSpot setup pages show the same general pattern of external credentials flowing into the self-hosted instance through environment variables and provider callback configuration. Daily uses an API key and an optional scale-plan flag. HubSpot uses a client identifier, client secret, OAuth redirect URL, and contact scopes. These pages reinforce a useful operational rule: finish schema migrations first, then apply environment and integration configuration, and then seed or repopulate app data where the docs require it. That ordering reduces confusion when debugging whether a missing integration is caused by schema state, secrets, callback URLs, or seed data.

Sources: apps/docs/content/apps/daily.mdx, apps/docs/content/apps/hubspot.mdx, apps/docs/content/apps/google.mdx

Operational Checklist and Next Steps

A safe migration workflow is deliberately boring. Before making a schema change, understand which application code will depend on it. After editing the Prisma schema, create a migration, name it clearly, and review the generated SQL or migration operations with special attention to destructive changes. Commit the migration with the code that requires it. During upgrades, apply the committed migrations with the documented workspace command rather than generating new ones on the server. If Prisma reports a non-empty database state mismatch, baseline the relevant migrations with the resolve command instead of trying random resets.

Sources: apps/docs/content/database-migrations.mdx

Next, read the installation and upgrading material that surrounds this page in the docs navigation, then review integration pages before enabling apps that require seeded app-store records or provider credentials. For migration failures, gather the exact Prisma error code, the database connection target, the migration name, and whether the database is local or production-like before making changes. That context determines whether you should deploy committed migrations, resolve already-applied migrations, or perform a local metadata reset. Treat production data as durable state, and prefer explicit, reviewed migration steps over automatic schema repair.

Sources: apps/docs/content/database-migrations.mdx, apps/docs/content/_meta.ts, apps/docs/content/apps/google.mdx