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

This addon adds Drizzle to your RedwoodSDK project.
These instructions assume you are starting with a RedwoodSDK project, for example from npx create-rwsdk -t minimal my-project-name.
To use your editor's AI agent support to add this addon for you (e.g. Cursor, VSCode Copilot):
npx create-rwsdk -t minimal my-project-name.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.
pnpm install
wrangler is working in your development environment.The first time you run pnpm dev it will install wrangler is working:
pnpm dev
pnpm add drizzle-orm
pnpm add drizzle-kit better-sqlite3 @libsql/client -D
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"
}
worker.tsx fileimport { 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, [...]),
]);
Run
npx wrangler types
This will update the environmental variable types.
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;
};
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(),
});
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",
src/db folder, create a new file called seed.tsInside 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);
},
};
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"
npx migrate:new
pnpm migrate:dev
pnpm migrate seed