Drizzle

The Drizzle Add-on for RedwoodSDK provides seamless database integration using Drizzle ORM, a lightweight and type-safe TypeScript ORM.

Drizzle

RedwoodSDK Drizzle Addon

This addon adds Drizzle to your RedwoodSDK project.

How to add it to your project

These instructions assume you are starting with a RedwoodSDK project, for example from npx create-rwsdk -t minimal my-project-name.

0. Decide whether to add this manually or via AI

To use your editor's AI agent support to add this addon for you (e.g. Cursor, VSCode Copilot):

  1. Make sure your project is open in your editor. You can create a new project with: npx create-rwsdk -t minimal my-project-name.
  2. Open a new AI chat window for your project
  3. Make sure you are in Agent mode
  4. Send the following chat prompt in the chat window - it will do the rest for you!
Please run the following and then follow the install instructions:

curl -s https://raw.githubusercontent.com/ahaywood/drizzle-addon/refs/heads/main/README.md -o /tmp/drizzle-addon-readme.md && cat /tmp/drizzle-addon-readme.md

Use these instructions to install the add-on in my RedwoodSDK project.

Alternatively, to apply this addon manually, simply follow the steps below.

1. Ensure all the project's dependecies have been installed

pnpm install

2. Ensure wrangler is working in your development environment.

The first time you run pnpm dev it will install wrangler is working:

pnpm dev

3. Add the following packages to your project, within your Terminal:

pnpm add drizzle-orm
pnpm add drizzle-kit better-sqlite3 @libsql/client -D

4. Create a D1 Database

npx wrangler d1 create <NAME-OF-DB>

When you run this command, the script will ask you if it can ad the configuration to your wrangler.jsonc file. You can say yes, but define the binding as DB.

For example, it will look like this:

"d1_databases": [
  {
    "binding": "DB",
    "database_name": "XXXXXX",
    "database_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "migrations_dir": "./drizzle"
  }

5. Update your worker.tsx file

import { defineApp } from "rwsdk/worker";
import { render, route } from "rwsdk/router";
import { drizzle } from "drizzle-orm/d1";

import { Document } from "@/app/Document";
import { setCommonHeaders } from "@/app/headers";
import { env } from "cloudflare:workers";

export interface Env {
  DB: D1Database;
}

export type AppContext = {
  db: ReturnType<typeof drizzle>;
};

export default defineApp([
  setCommonHeaders(),
  ({ ctx }) => {
    ctx.db = drizzle(env.DB);
  },
  render(Document, [...]),
]);

6. Update the Types

Run

npx wrangler types

This will update the environmental variable types.

7. Inside the app directory, create a new folder called lib. Inside create a new file called db.ts. Inside the file, add the following:

import { drizzle } from "drizzle-orm/d1";
import { Env } from "@/worker";

export const setupDb = (env: Env) => {
  const db = drizzle(env.DB);
  return db;
};

8. Inside the src directory, create a folder called db and inside add a schema.ts file.

Add the following to the new file:

// schema.ts
import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const users = sqliteTable("users", {
  id: int().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  email: text().notNull().unique(),
});

9. In the root of your project, create a drizzle.config.ts file:

Inside the new file, add the following contents:

import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/db/schema.ts",
  dbCredentials: {
    url: "...",
  },
});

The url will need to match the SQLite database inside the .wrangler/state/v3/d1/miniflare-D1DatabaseObject. It will look something like this:

url: "./.wrangler/state/v3/d1/miniflare-D1DatabaseObject/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.sqlite",

10. Inside the src/db folder, create a new file called seed.ts

Inside the new file, include the following contents:

import { drizzle } from "drizzle-orm/d1";
import { users } from "./schema";

export interface Env {
  DB: D1Database;
}

export default {
  async fetch(request: Request, env: Env) {
    const db = drizzle(env.DB);
    // Insert a user
    await db.insert(users).values({
      name: "Test",
      email: "joe@test.com",
    });
    // Verify the insert by selecting all users
    const result = await db.select().from(users).all();
    return Response.json(result);
  },
};

11. Add the following scripts section of the package.json file:

"migrate:new": "drizzle-kit generate",
"migrate:dev": "wrangler d1 migrations apply DB --local",
"seed": "npm run worker:run ./src/db/seed.ts",
"studio": "npx drizzle-kit studio"

12. Run the following command to generate tee first migration:

npx migrate:new

13. Then, run the following command to apply the migration:

pnpm migrate:dev

14. Run the seed command to to add the first user to the database

pnpm migrate seed