Skip to content
GitHubXDiscordRSS

PlanetScale + Drizzle

Deploy a PlanetScale database with Drizzle migrations using Alchemy.

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_ORGANIZATION=your_organization_name
    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:

    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",
    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`,
    database,
    parentBranch: database.defaultBranch,
    isProduction: false,
    safeMigrations: !app.local,
    });
    // Create credentials for the branch
    const password = await Password("Password", {
    name: `${app.name}-${app.stage}-password`,
    database,
    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