Skip to content
GitHubXDiscordRSS

PlanetScale + Drizzle

This guide shows how to create and manage PlanetScale databases with automated Drizzle migrations using Alchemy.

  1. Install dependencies

    Add the required dependencies to your project:

    Terminal window
    bun add @planetscale/database drizzle-orm
    bun add -D drizzle-kit
  2. Set credentials

    Create a PlanetScale account and get your API credentials. Add them to your .env file:

    Terminal window
    PLANETSCALE_ORG_ID=your_organization_id
    PLANETSCALE_API_TOKEN=your_api_token
  3. Define schema

    Create your database schema:

    src/schema.ts
    import { mysqlTable, serial, varchar } from "drizzle-orm/mysql-core";
    export const sampleTable = mysqlTable("sample_table", {
    id: serial("id").primaryKey(),
    value: varchar("value", { length: 255 }).notNull(),
    });
  4. Configure Drizzle

    Add Drizzle configuration and scripts:

    drizzle.config.ts
    import { defineConfig } from "drizzle-kit";
    export default defineConfig({
    out: "./drizzle",
    schema: "./src/schema.ts",
    dialect: "mysql",
    dbCredentials: {
    url: `mysql://${process.env.DATABASE_USERNAME}:${process.env.DATABASE_PASSWORD}@${process.env.DATABASE_HOST}/${process.env.DATABASE_NAME}?ssl={"rejectUnauthorized":true}`,
    },
    });
    package.json
    {
    "scripts": {
    "db:generate": "drizzle-kit generate",
    "db:migrate": "drizzle-kit migrate",
    "db:studio": "drizzle-kit studio"
    }
    }
  5. Create your infrastructure

    Create alchemy.run.ts to provision PlanetScale resources and run migrations:

    /// <reference types="@types/node" />
    import alchemy from "alchemy";
    import { Database, Branch, Password } from "alchemy/planetscale";
    import { Exec } from "alchemy/os";
    const app = await alchemy("my-planetscale-app");
    // Create the database
    const database = await Database("Database", {
    adopt: true,
    name: "sample-database",
    organizationId: process.env.PLANETSCALE_ORG_ID!,
    region: {
    slug: "us-east",
    },
    clusterSize: "PS_10",
    allowDataBranching: true,
    automaticMigrations: true,
    requireApprovalForDeploy: false,
    defaultBranch: "main",
    migrationFramework: "other",
    migrationTableName: "__drizzle_migrations",
    });
    // Create a branch for this environment
    const branch = await Branch("Branch", {
    adopt: true,
    name: `${app.name}-${app.stage}-branch`,
    organizationId: process.env.PLANETSCALE_ORG_ID!,
    databaseName: database.name,
    parentBranch: database.defaultBranch,
    isProduction: false,
    safeMigrations: !app.local,
    });
    // Create credentials for the branch
    const password = await Password("Password", {
    name: `${app.name}-${app.stage}-password`,
    organizationId: process.env.PLANETSCALE_ORG_ID!,
    database: database,
    branch: branch,
    role: "admin",
    });
    // Generate and run migrations
    await Exec("DrizzleGenerate", {
    command: "bun run db:generate",
    env: {
    DATABASE_NAME: database.name,
    DATABASE_HOST: password.host,
    DATABASE_USERNAME: password.username,
    DATABASE_PASSWORD: password.password,
    },
    });
    await Exec("DrizzleMigrate", {
    command:
    process.platform === "win32"
    ? `cmd /C "bun run db:migrate || if %ERRORLEVEL%==9 exit 0 else exit %ERRORLEVEL%"`
    : `sh -c 'bun run db:migrate || ( [ $? -eq 9 ] && exit 0 ); exit $?'`,
    env: {
    DATABASE_NAME: database.name,
    DATABASE_HOST: password.host,
    DATABASE_USERNAME: password.username,
    DATABASE_PASSWORD: password.password,
    },
    });
    // Start Drizzle Studio in local development
    if (app.local) {
    Exec("DrizzleStudio", {
    command: "bun run db:studio",
    env: {
    DATABASE_NAME: database.name,
    DATABASE_HOST: password.host,
    DATABASE_USERNAME: password.username,
    DATABASE_PASSWORD: password.password,
    },
    });
    }
    console.log({
    database: database.name,
    branch: branch.name,
    host: password.host,
    });
    await app.finalize();
  6. Deploy your stack

    Run alchemy.run.ts to deploy:

    Terminal window
    bun alchemy deploy

    It should log your database connection details:

    Terminal window
    {
    database: "sample-database",
    branch: "my-planetscale-app-dev-branch",
    host: "aws.connect.psdb.cloud"
    }
  7. (Optional) Tear down

    Clean up all PlanetScale resources created by this stack:

    Terminal window
    bun alchemy destroy