Skip to content

Commit

Permalink
d1 docs (#5746)
Browse files Browse the repository at this point in the history
* d1 instructions in cf workers deployment docs

* add notes about d1 to driver adapters docs

* add D1 to supported DBs

* Update content/200-orm/050-overview/500-databases/950-cloudflare-d1.mdx

* Update content/200-orm/200-prisma-client/500-deployment/301-edge/450-deploy-to-cloudflare.mdx

* Update content/200-orm/050-overview/500-databases/200-database-drivers.mdx

Co-authored-by: Jan Piotrowski <[email protected]>

* Update content/200-orm/050-overview/500-databases/200-database-drivers.mdx

Co-authored-by: Jan Piotrowski <[email protected]>

* continue d1 docs

* continue d1 docs

* continue d1 docs

* Update content/200-orm/200-prisma-client/500-deployment/301-edge/450-deploy-to-cloudflare.mdx

* Update content/200-orm/200-prisma-client/500-deployment/301-edge/450-deploy-to-cloudflare.mdx

* Update content/200-orm/200-prisma-client/500-deployment/301-edge/450-deploy-to-cloudflare.mdx

Co-authored-by: Jan Piotrowski <[email protected]>

* add info about migration workflows

* add info about migration workflows

* fix typo

* update d1 docs

* update d1 docs

* Update content/200-orm/200-prisma-client/500-deployment/301-edge/450-deploy-to-cloudflare.mdx

Co-authored-by: Jan Piotrowski <[email protected]>

* add notes about bootstrapping a project

* add link to feedback discussion

* update instructions for d1

* Update content/200-orm/200-prisma-client/500-deployment/301-edge/450-deploy-to-cloudflare.mdx

Co-authored-by: Alberto Schiabel <[email protected]>

* update instructions for d1

* update instructions for d1

* update instructions for d1 to use --from-local-d1

* Update content/200-orm/050-overview/500-databases/950-cloudflare-d1.mdx

Co-authored-by: Alberto Schiabel <[email protected]>

* fix typos

---------

Co-authored-by: Jan Piotrowski <[email protected]>
Co-authored-by: Jon Harrell <[email protected]>
Co-authored-by: Alberto Schiabel <[email protected]>
  • Loading branch information
4 people authored Apr 2, 2024
1 parent 3347858 commit fcd00ac
Show file tree
Hide file tree
Showing 9 changed files with 473 additions and 6 deletions.
1 change: 1 addition & 0 deletions cSpell.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"MSSQLSERVER",
"neovim",
"Nestjs",
"Overfetching",
"pgbouncer",
"planetscale",
"pooler",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Prisma ORM maintains the following serverless driver adapters:

- [Neon](/orm/overview/databases/neon#how-to-use-neons-serverless-driver-with-prisma-orm-preview)
- [PlanetScale](/orm/overview/databases/planetscale#how-to-use-the-planetscale-serverless-driver-with-prisma-orm-preview)
- [Cloudflare D1](orm/overview/databases/cloudflare-d1)

### Community-maintained database driver adapters

Expand Down Expand Up @@ -69,9 +70,11 @@ To use this feature:

3. Refer to the following pages to learn more how to use the specific driver adapters with the specific database providers:

- [PostgreSQL](/orm/overview/databases/postgresql#using-the-node-postgres-driver)
- [Neon](/orm/overview/databases/neon#how-to-use-neons-serverless-driver-with-prisma-orm-preview)
- [PlanetScale](/orm/overview/databases/planetscale#how-to-use-the-planetscale-serverless-driver-with-prisma-orm-preview)
- [Turso](/orm/overview/databases/turso#how-to-connect-and-query-a-turso-database)
- [Cloudflare D1](/orm/overview/databases/cloudflare-d1)

## Notes about using driver adapters

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ PlanetScale's branching model and design for scalability means that there are al

- **Branching and deploy requests.** PlanetScale provides two types of database branches: _development branches_, which allow you to test out schema changes, and _production branches_, which are protected from direct schema changes. Instead, changes must be first created on a development branch and then deployed to production using a deploy request. Production branches are highly available and include automated daily backups. To learn more, see [How to use branches and deploy requests](#how-to-use-branches-and-deploy-requests).
- **Referential actions and integrity.** To support scaling across multiple database servers, PlanetScale [by default does not use foreign key constraints](https://planetscale.com/docs/learn/operating-without-foreign-key-constraints), which are normally used in relational databases to enforce relationships between data in different tables, and asks users to handle this manually in their applications. However, you can explicitly [enable them in the PlanetScale database settings](https://planetscale.com/docs/concepts/foreign-key-constraints). If you don't enable these explicitly, you can still maintain these relationships in your data and allow the use of [referential actions](/orm/prisma-schema/data-model/relations/referential-actions) by using Prisma ORM's ability to [emulate relations in Prisma Client](/orm/prisma-schema/data-model/relations/relation-mode#emulate-relations-in-prisma-orm-with-the-prisma-relation-mode) with the `prisma` relation mode. For more information, see [How to emulate relations in Prisma Client](#option-1-emulate-relations-in-prisma-client).
- **Creating indexes on foreign keys.** When [emulating relations in Prisma ORM](#option-1-emulate-relations-in-prisma-client) (i.e. when _not_ using foreign key constraints on the database-level), you will need to create dedicated indexes on foreign keys. In a standard MySQL database, if a table has a column with a foreign key constraint, an index is automatically created on that column. When PlanetScale is configured to not use foreign key constraints, these indexes are [currently](https://github.com/prisma/prisma/issues/10611) not created when Prisma Client emulates relations, which can lead to issues with queries not being well optimised. To avoid this, you can create indexes in Prisma ORM. For more information, see [How to create indexes on foreign keys](#2-create-indexes-on-foreign-keys).
- **Creating indexes on foreign keys.** When [emulating relations in Prisma ORM](#option-1-emulate-relations-in-prisma-client) (i.e. when _not_ using foreign key constraints on the database-level), you will need to create dedicated indexes on foreign keys. In a standard MySQL database, if a table has a column with a foreign key constraint, an index is automatically created on that column. When PlanetScale is configured to not use foreign key constraints, these indexes are [currently](https://github.com/prisma/prisma/issues/10611) not created when Prisma Client emulates relations, which can lead to issues with queries not being well optimized. To avoid this, you can create indexes in Prisma ORM. For more information, see [How to create indexes on foreign keys](#2-create-indexes-on-foreign-keys).
- **Making schema changes with `db push`.** When you merge a development branch into your production branch, PlanetScale will automatically compare the two schemas and generate its own schema diff. This means that Prisma ORM's [`prisma migrate`](/orm/prisma-migrate) workflow, which generates its own history of migration files, is not a natural fit when working with PlanetScale. These migration files may not reflect the actual schema changes run by PlanetScale when the branch is merged.

<Admonition type="warning">
Expand Down Expand Up @@ -108,7 +108,7 @@ model Comment {
}
```

The `postId` field in the `Comment` model refers to the corresponding `id` field in the `Post` model. However this is not implemented as a foreign key in PlanetScale, so the column doesn't have an automatic index. This means that some queries may not be well optimised. For example, if you query for all comments with a certain post `id`, PlanetScale may have to do a full table lookup. This could be slow, and also expensive because PlanetScale's billing model charges for the number of rows read.
The `postId` field in the `Comment` model refers to the corresponding `id` field in the `Post` model. However this is not implemented as a foreign key in PlanetScale, so the column doesn't have an automatic index. This means that some queries may not be well optimized. For example, if you query for all comments with a certain post `id`, PlanetScale may have to do a full table lookup. This could be slow, and also expensive because PlanetScale's billing model charges for the number of rows read.

To avoid this, you can define an index on the `postId` field using [Prisma ORM's `@@index` argument](/orm/reference/prisma-schema-reference#index):

Expand Down
252 changes: 252 additions & 0 deletions content/200-orm/050-overview/500-databases/950-cloudflare-d1.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
---
title: 'Cloudflare D1'
metaTitle: 'Cloudflare D1'
metaDescription: 'Guide to Cloudflare D1'
tocDepth: 3
preview: true
---

<TopBlock>

This guide discusses the concepts behind using Prisma ORM and Cloudflare D1, explains the commonalities and differences between Cloudflare D1 and other database providers, and leads you through the process for configuring your application to integrate with Cloudflare D1.

Prisma ORM support for Cloudflare D1 is currently in [Preview](/orm/more/releases#preview). We would appreciate your feedback [on GitHub](https://github.com/prisma/prisma/discussions/23646).

</TopBlock>

## What is Cloudflare D1?

D1 is Cloudflare's native serverless database and was initially [launched in 2022](https://blog.cloudflare.com/introducing-d1). It's based on SQLite and can be used when deploying applications with Cloudflare. D1 .

Following Cloudflare's principles of geographic distribution and bringing compute and data closer to application users, D1 supports automatic read-replication. It dynamically manages the number of database instances and locations of read-only replicas based on how many queries a database is getting, and from where.

For write-operations, queries travel to a single primary instance in order to propagate the changes to all read-replicas and ensure data consistency.

## Commonalities with other database providers

D1 is based on SQLite.

Many aspects of using Prisma ORM with D1 are just like using Prisma ORM with any other relational database. You can still:

- model your database with the [Prisma Schema Language](/orm/prisma-schema)
- use Prisma ORM's existing [`sqlite` database connector](/orm/overview/databases/sqlite) in your schema
- use [Prisma Client](/orm/prisma-client) in your application to talk to the database server at D1

## Differences to consider

There are a number of differences between D1 and SQLite to consider. You should be aware of the following when deciding to use D1 and Prisma ORM:

- **Local and remote D1 (SQLite) databases**. Cloudflare provides local and remote versions of D1. The [local](https://developers.cloudflare.com/d1/configuration/local-development) version is managed using the `--local` option of the `wrangler d1` CLI and is located in `.wrangler/state`. The [remote](https://developers.cloudflare.com/d1/configuration/remote-development) version is managed by Cloudflare and is accessed via HTTP.
- **Making schema changes**. Since D1 uses HTTP to connect to the remote database, this makes it incompatible with some commands of Prisma Migrate, like `prisma migrate dev`. However, you can use D1's [migration system](https://developers.cloudflare.com/d1/reference/migrations/) and the [`prisma migrate diff`](/orm/reference/prisma-cli-reference#migrate-diff) command for your migration workflows. See the [Migration workflows](#migration-workflows) below for more information.

## How to connect to D1 in Cloudflare Workers or Cloudflare pages

When using Prisma ORM with D1, you need to use the `sqlite` database provider and the `@prisma/adapter-d1` [driver adapter](/orm/overview/databases/database-drivers#driver-adapters).

If you want to deploy a Cloudflare Worker with D1 and Prisma ORM, follow these [step-by-step instructions](/orm/prisma-client/deployment/edge/deploy-to-cloudflare#d1).

## Migration workflows

Cloudflare D1 comes with its own [migration system](https://developers.cloudflare.com/d1/reference/migrations/). We recommend that you use this migration system via the `wrangler d1 migrations` command to create and manage migration files on your file system.

This command doesn't help you in figuring out the SQL statements for creating your database schema that need to be put _inside_ of these migration files though. If you want to query your database using Prisma Client, it's important that your database schema maps to your Prisma schema, this is why it's recommended to generated the SQL statements from your Prisma schema.

When using D1, you can use the [`prisma migrate diff`](/orm/reference/prisma-cli-reference#migrate-diff) command for that purpose.

### Creating an initial migration

The workflow for creating an initial migration looks as follows. Assume you have a fresh D1 instance without any tables.

#### 1. Update your Prisma data model

This is your initial version of the Prisma schema that you want to map to your D1 instance:

```prisma
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
```

#### 2. Create migration file using `wrangler` CLI

Next, you need to create the migration file using the [`wrangler d1 migrations create`](https://developers.cloudflare.com/workers/wrangler/commands/#migrations-create) command:

```terminal
npx wrangler d1 migrations create __YOUR_DATABASE_NAME__ create_user_table
```

Since this is the very first migration, this command will prompt you to also create a `migrations` folder. Note that if you want your migration files to be stored in a different location, you can [customize it using Wrangler](https://developers.cloudflare.com/d1/reference/migrations/#wrangler-customizations).

Once the command has executed and assuming you have chosen the default `migrations` name for the location of your migration files, the command has created the following folder and file for you:

```no-copy
migrations/
└── 0001_create_user_table.sql
```

However, before you can apply the migration to your D1 instance, you actually need to put a SQL statement into the currently empty `0001_create_user_table.sql` file.

#### 3. Generate SQL statements using `prisma migrate diff`

To generate the initial SQL statement, you can use the `prisma migrate diff` command which compares to _schemas_ (via its `--to-X` and `--from-X` options) and generates the steps that are needed to "evolve" from one to the other. These schemas can be either Prisma or SQL schemas.

For the initial migration, you can use the special `--from-empty` option though:

```terminal
npx prisma migrate diff \
--from-empty \
--to-schema-datamodel ./prisma/schema.prisma \
--script > migrations/0001_create_user_table.sql
```

The command above uses the following options:

- `--from-empty`: The source for the SQL statement is an empty schema.
- `--to-schema-datamodel ./prisma/schema.prisma`: The target for the SQL statement is the data model in `./prisma/schema.prisma`.
- `--script`: Output the result as SQL. If you omit this option, the "migration steps" will be generated in plain English.
- `> migrations/0001_create_user_table.sql`: Store the result in `migrations/0001_create_user_table.sql`.

After running this command, `migrations/0001_create_user_table.sql` will have the following contents:

```sql file=migrations/0001_create_user_table.sql no-copy
-- CreateTable
CREATE TABLE "User" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"email" TEXT NOT NULL,
"name" TEXT
);

-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
```

#### 4. Execute the migration using `wrangler d1 migrations apply`

Finally, you can apply the migration against your D1 instances.

For the **local** instance, run:

```terminal
npx wrangler d1 migrations apply __YOUR_DATABASE_NAME__ --local
```

For the **remote** instance, run:

```terminal
npx wrangler d1 migrations apply __YOUR_DATABASE_NAME__ --remote
```

### Evolve your schema with further migrations

For any further migrations, you can use the same workflow but instead of using `--from-empty`, you'll need to use `--from-local-d1` because your source schema for the `prisma migrate diff` command now is the current schema of that local D1 instance, while the target remains your (then updated) Prisma schema.

<!-- For any further migrations, you can use the same workflow but instead of using `--from-empty`, you'll need to use `--from-url __FILE_PATH_` (where `__FILE_PATH_` points to your local D1 instance) because your source schema for the `prisma migrate diff` command now is the current schema of that local D1 instance, while the target remains your (then updated) Prisma schema. -->

<!-- #### 1. Locate the SQLite database file in `.wrangler`

Your local D1 instance is represented by a SQLite database file that's stored in `./wrangler/state/d1`. Locate this file and grab the full path to the SQLite database instance. It likely looks similar to this:

```no-copy
./.wrangler/state/v3/d1/miniflare-D1DatabaseObject/0fee8d0e0152078a4a36c1a547dec875c1c7aa598e931fbbefdd7bff19d3d60d.sqlite
```

Keep this file path handy since you'll need it for any future migrations. The instructions will refer to the file path as:

```
./.wrangler/state/v3/d1/miniflare-D1DatabaseObject/__YOUR_DB__.sqlite
``` -->

#### 1. Update your Prisma data model

Assume you have updated your Prisma schema with another model:

```prisma
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id])
authorId Int
}
```
#### 2. Create migration file using `wrangler` CLI
Like before, you first need to create the migration file:
```terminal
npx wrangler d1 migrations create __YOUR_DATABASE_NAME__ create_post_table
```
Once the command has executed (again assuming you have chosen the default `migrations` name for the location of your migration files), the command has created a new file inside of the `migrations` folder:
```no-copy
migrations/
├── 0001_create_user_table.sql
└── 0002_create_post_table.sql
```
As before, you now need to put a SQL statement into the currently empty `0002_create_post_table.sql` file.
#### 3. Generate SQL statements using `prisma migrate diff`
As explained above, you now need to use `--from-local-d1` instead of `--from-empty` to specify a source schema:
```terminal
npx prisma migrate diff \
--from-local-d1 \
--to-schema-datamodel ./prisma/schema.prisma \
--script > migrations/0002_create_post_table.sql
```
<!-- ```terminal
npx prisma migrate diff \
--from-url file:./.wrangler/state/v3/d1/miniflare-D1DatabaseObject/__YOUR_DB__.sqlite \
--to-schema-datamodel ./prisma/schema.prisma \
--script > migrations/0002_create_post_table.sql
```
> **Note**: Remember that you need to replace `__YOUR_DB__` with the long string of numbers and characters that represent the file name of your local D1 instance. -->
The command above uses the following options:
- `--from-local-d1`: The source for the SQL statement is the local D1 database file.
- `--to-schema-datamodel ./prisma/schema.prisma`: The target for the SQL statement is the data model in `./prisma/schema.prisma`.
- `--script`: Output the result as SQL. If you omit this option, the "migration steps" will be generated in plain English.
- `> migrations/0002_create_post_table.sql`: Store the result in `migrations/0002_create_post_table.sql`.
After running this command, `migrations/0002_create_post_table.sql` will have the following contents:
```sql file=migrations/0002_create_post_table.sql no-copy
-- CreateTable
CREATE TABLE "Post" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"title" TEXT NOT NULL,
"authorId" INTEGER NOT NULL,
CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
```
#### 4. Execute the migration using `wrangler d1 migrations apply`
Finally, you can apply the migration against your D1 instances.
For the **local** instance, run:
```terminal
npx wrangler d1 migrations apply __YOUR_DATABASE_NAME__ --local
```
For the **remote** instance, run:
```terminal
npx wrangler d1 migrations apply __YOUR_DATABASE_NAME__ --remote
```
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Here is an overview of the different database drivers and their compatibility wi
- [PlanetScale Serverless](https://planetscale.com/docs/tutorials/planetscale-serverless-driver) uses HTTP to access the database. It works with Cloudflare Workers and Vercel Edge Functions.
- [`node-postgres`](https://node-postgres.com/) (`pg`) uses Cloudflare's `connect()` (TCP) to access the database. It is only compatible with Cloudflare Workers, not with Vercel Edge Functions.
- [`@libsql/client`](https://github.com/tursodatabase/libsql-client-ts) is used to access Turso databases. It works with Cloudflare Workers and Vercel Edge Functions.
- [Cloudflare D1](https://developers.cloudflare.com/d1/) is used to access D1 databases. It is only compatible with Cloudflare Workers, not with Vercel Edge Functions.

There's [also work being done](https://github.com/sidorares/node-mysql2/pull/2289) on the `node-mysql2` driver which will enable access to traditional MySQL databases from Cloudflare Workers and Pages in the future as well.

Expand All @@ -50,6 +51,7 @@ Depending on which deployment provider and database/driver you use, there may be
- [PostgreSQL (traditional)](/orm/prisma-client/deployment/edge/deploy-to-cloudflare#postgresql-traditional)
- [PlanetScale](/orm/prisma-client/deployment/edge/deploy-to-cloudflare#planetscale)
- [Neon](/orm/prisma-client/deployment/edge/deploy-to-cloudflare#neon)
- [Cloudflare D1](/orm/prisma-client/deployment/edge/deploy-to-cloudflare#d1)
- Vercel
- [Vercel Postgres](/orm/prisma-client/deployment/edge/deploy-to-vercel#vercel-postgres)
- [Neon](/orm/prisma-client/deployment/edge/deploy-to-vercel#neon)
Expand Down
Loading

0 comments on commit fcd00ac

Please sign in to comment.