diff --git a/src/content/docs/d1/reference/community-projects.mdx b/src/content/docs/d1/reference/community-projects.mdx index a095bb554ff..7a892eae6dd 100644 --- a/src/content/docs/d1/reference/community-projects.mdx +++ b/src/content/docs/d1/reference/community-projects.mdx @@ -62,6 +62,16 @@ Drizzle is a headless TypeScript ORM with a head which runs on Node, Bun and Den * [GitHub](https://github.com/drizzle-team/drizzle-orm) * [D1 example](https://orm.drizzle.team/docs/connect-cloudflare-d1) +:::caution[Using Drizzle migrations with D1] + +When using Drizzle with D1, be aware of the following: + +- **`drizzle-kit migrate` does not work with D1.** Drizzle cannot apply migrations to D1 directly because D1 requires Cloudflare's API for writes. Use `drizzle-kit generate` to create the SQL migration files, then apply them with `wrangler d1 migrations apply`. Refer to [Nested migration layouts](/d1/reference/migrations/#nested-migration-layouts) for how to configure `wrangler` to read Drizzle's output folder. +- **`drizzle-kit generate` will try to drop tables not in your schema file.** Drizzle assumes it owns every table in the database. Tables that exist in the database but are not defined in your TypeScript schema — including the `d1_migrations` tracking table and Cloudflare's internal `_cf_KV` table — will appear as `DROP TABLE` statements in generated migrations. Always review generated SQL before applying. To prevent this, add `tablesFilter` to your `drizzle.config.ts`: `["!d1_migrations", "!_cf_KV", "!sqlite_sequence"]`. If you customized the tracking table name via `migrations_table` in your Wrangler configuration, use that name instead of `d1_migrations`. +- **Drizzle and `wrangler` track migrations separately.** `wrangler` records applied migrations in the `d1_migrations` table. Drizzle tracks them in `drizzle/meta/_journal.json`. These two systems do not communicate. If you use both, let `wrangler` handle tracking and use Drizzle only for SQL generation. + +::: + ### workers-qb `workers-qb` is a zero-dependency query builder that provides a simple standardized interface while keeping the benefits and speed of using raw queries over a traditional ORM. While not intended to provide ORM-like functionality, `workers-qb` makes it easier to interact with your database from code for direct SQL access. diff --git a/src/content/docs/d1/reference/migrations.mdx b/src/content/docs/d1/reference/migrations.mdx index 750ef2da17d..86637d8a2a4 100644 --- a/src/content/docs/d1/reference/migrations.mdx +++ b/src/content/docs/d1/reference/migrations.mdx @@ -86,6 +86,34 @@ The pattern is a standard glob — `*` matches one path segment, `**` matches an `wrangler d1 migrations create` only writes top-level files inside `migrations_dir`, so if your `migrations_pattern` only matches nested files (as with the Drizzle layout), generate new migrations using your ORM's command (for example, `drizzle-kit generate`) instead. +## Generate migrations with an ORM + +You can use an object-relational mapping (ORM) tool like [Drizzle](https://orm.drizzle.team/) or [Prisma](https://www.prisma.io/) to generate migration SQL instead of writing it by hand. With an ORM, you define your schema in TypeScript (or a schema file), and the ORM's CLI detects changes and outputs `.sql` migration files. + +ORMs cannot apply migrations to D1 directly. D1 requires Cloudflare's API for writes, so you must use `wrangler` to apply the generated SQL. The workflow is: + +1. Define or edit your schema in TypeScript (or your ORM's schema format). +2. Run your ORM's migration generation command (for example, `drizzle-kit generate`) to produce a `.sql` file. +3. Review the generated SQL for destructive statements. ORMs may generate `DROP TABLE` statements for tables they do not manage, such as the `d1_migrations` tracking table. +4. Apply the migration with `wrangler d1 migrations apply`. + +To connect an ORM's migration output folder to `wrangler`, use `migrations_dir` and `migrations_pattern` in your [Wrangler configuration](#wrangler-customizations). Refer to [Nested migration layouts](#nested-migration-layouts) for an example using Drizzle's subdirectory layout. + +### ORM vs. raw SQL + +Raw SQL migrations with `wrangler` work well when you have a small number of tables, your queries are basic, you are comfortable writing SQL, or you are the only developer on the project. + +An ORM starts to pay off in the following situations: + +- Your schema grows to many tables with foreign key relationships. +- You build complex queries with joins across multiple tables and want compile-time type safety. +- Multiple developers touch the schema and need a single TypeScript definition as the source of truth. +- You want editor autocompletion when writing queries. + +Either way, always review migration SQL before applying to production. + +For a list of ORMs, query builders, and tools that work with D1, refer to [Community projects](/d1/reference/community-projects/). + ## Foreign key constraints When applying a migration, you may need to temporarily disable [foreign key constraints](/d1/sql-api/foreign-keys/). To do so, call `PRAGMA defer_foreign_keys = true` before making changes that would violate foreign keys.