1---
2title: Drizzle ORM with PlanetScale
3description: Configure PlanetScale Postgres or MySQL branches, committed Drizzle migrations, and role or password connections.
4---
5
6Use the portable [Postgres](/sql/drizzle/postgres) or [MySQL](/sql/drizzle/mysql) client with PlanetScale. This page owns database configuration; [Add Drizzle ORM](/cloudflare/data/drizzle) owns Worker deployment.
7
8## Define the schema
9
10```typescript
11// drizzle.config.ts
12import { defineConfig } from "drizzle-kit";
13
14export default defineConfig({
15 schema: "./src/schema.ts",
16 out: "./migrations",
17 dialect: "postgresql",
18});
19```
20
21Use the [Postgres schema example](/sql/drizzle/postgres#define-the-schema) with `pg-core` columns, or select `dialect: "mysql"` with the [MySQL schema](/sql/drizzle/mysql#define-the-schema).
22
23## Generate and review migrations
24
25```sh
26bunx drizzle-kit generate
27git diff -- src/schema.ts migrations
28git status --short
29git add src/schema.ts drizzle.config.ts migrations
30git diff --cached
31git commit -m "Add database migration"
32```
33
34Generate when the schema changes, then review and commit the schema, SQL, and snapshots together before deploying. The optional [`Drizzle.Schema` resource](/providers/drizzle/schema) is not required for this workflow.
35
36## Apply them on the branch
37
38```typescript
39// src/Db.ts
40import * as Planetscale from "alchemy/Planetscale";
41import * as Effect from "effect/Effect";
42
43export const PlanetscaleDb = Effect.gen(function* () {
44 const database = yield* Planetscale.PostgresDatabase("app-db", {
45 region: { slug: "us-east" },
46 clusterSize: "PS_10",
47 });
48 const branch = yield* Planetscale.PostgresBranch("app-branch", {
49 database,
50 migrations: "./migrations",
51 });
52 const role = yield* Planetscale.PostgresRole("app-role", {
53 database,
54 branch,
55 inheritedRoles: ["postgres"],
56 });
57 return { database, branch, role };
58});
59```
60
61Register `Planetscale.providers()` in your Stack; the branch applies committed migrations transactionally and the role supplies application credentials. [Postgres](/planetscale/data/postgres) covers branch and role options.
62
63## Connect via `origin` / `pooledOrigin`
64
65```typescript
66import * as Cloudflare from "alchemy/Cloudflare";
67
68export const Hyperdrive = Effect.gen(function* () {
69 const { role } = yield* PlanetscaleDb;
70 return yield* Cloudflare.Hyperdrive.Connection("app-hyperdrive", {
71 origin: role.origin,
72 dev: role.pooledOrigin,
73 caching: { disabled: true },
74 });
75});
76```
77
78`role.origin` uses direct port 5432, while `role.pooledOrigin` uses PSBouncer on port 6432. Other runtimes can consume the redacted `connectionUrl` or `connectionUrlPooled`; the [Cloudflare walkthrough](/cloudflare/data/drizzle) continues from this Hyperdrive resource.
79
80## MySQL: generate and check in migrations
81
82```diff lang="typescript"
83// drizzle.config.ts
84- dialect: "postgresql",
85+ dialect: "mysql",
86```
87
88For Vitess, use `mysql-core` columns and run the same generate, review, and commit commands above. Do not reuse Postgres migration SQL on a MySQL branch.
89
90## MySQL: apply and connect
91
92```typescript
93// src/Db.ts
94import * as Planetscale from "alchemy/Planetscale";
95import * as Effect from "effect/Effect";
96
97export const PlanetscaleDb = Effect.gen(function* () {
98 const database = yield* Planetscale.MySQLDatabase("app-db", {
99 region: { slug: "us-east" },
100 clusterSize: "PS_10",
101 });
102 const branch = yield* Planetscale.MySQLBranch("app-branch", {
103 database,
104 isProduction: false,
105 migrations: "./migrations",
106 });
107 const password = yield* Planetscale.MySQLPassword("app-password", {
108 database,
109 branch,
110 role: "readwriter",
111 });
112 return { database, branch, password };
113});
114```
115
116`MySQLPassword` provides `password.origin` for Hyperdrive, without a pooled variant. [PlanetScale migrations](/planetscale/data/migrations) covers statement splitting and MySQL's non-transactional DDL behavior.
117
118## Deploy committed files
119
120```sh
121bun alchemy deploy
122```
123
124The branch applies pending committed files; this configuration does not generate SQL during deployment. If `drizzle-kit migrate` already owns application, keep that workflow unless you deliberately choose Alchemy-managed migrations; see [migration ownership](/sql/drizzle/migrations).
125
126## Wire it into your runtime
127
128Follow [Add Drizzle ORM](/cloudflare/data/drizzle) for Worker bindings, or [SQL databases](/sql/databases) to choose a client for another runtime. Existing [Postgres](https://github.com/alchemy-run/alchemy/tree/main/examples/cloudflare-planetscale-postgres-drizzle) and [MySQL](https://github.com/alchemy-run/alchemy/tree/main/examples/cloudflare-planetscale-mysql-drizzle) projects demonstrate connections and queries, but use the optional schema resource rather than this guide's generation workflow.
129
130## Where next
131
132Read [Preview branches per PR](/planetscale/guides/preview-branches) for branch provisioning, and [Postgres](/planetscale/data/postgres) or [MySQL](/planetscale/data/mysql) for database-specific behavior.