Cloudflare Redwood
This guide demonstrates how to deploy a Redwood application with Drizzle to Cloudflare using Alchemy.
Create a new Redwood Project
Start by creating a new Redwood project using the Drizzle template:
bunx degit redwoodjs/example-drizzle my-cloudflare-app
cd my-cloudflare-app
bun install
Install cloudflare
and alchemy
:
bun add alchemy cloudflare
Create alchemy.run.ts
// ./alchemy.run.ts
import "alchemy/cloudflare";
import alchemy from "alchemy";
import { D1Database, Redwood } from "alchemy/cloudflare";
const app = await alchemy("cloudflare-redwood", {
stage: process.env.USER ?? "dev",
phase: process.argv.includes("--destroy") ? "destroy" : "up",
quiet: process.argv.includes("--verbose") ? false : true,
});
// (resources go here)
await app.finalize(); // must be at end
NOTE
See the Getting Started guide if this is unfamiliar.
Create Redwood and Database
Import the Redwood
and D1Database
resources to configure your application:
const database = await D1Database("redwood-db", {
name: "redwood-db",
migrationsDir: "drizzle",
});
export const website = await Redwood("redwood-website", {
bindings: {
DB: database,
},
});
Log out the website's URL:
console.log({
url: website.url
})
Deploy Redwood Application
Login to Cloudflare:
wrangler login
Run alchemy.run.ts
script to deploy:
bun ./alchemy.run
It should log out the URL of your deployed site:
{
url: "https://your-site.your-sub-domain.workers.dev",
}
Click the endpoint to see your Redwood application!
Working with Drizzle Schema and Migrations
The Redwood Drizzle template includes a database schema defined using Drizzle ORM. Let's explore and modify the schema.
Understanding the Existing Schema
The schema files are located in the api/db
directory. Take a look at the existing schema:
cat api/db/schema.ts
The default schema typically includes a basic user model. Let's modify this schema to add a posts table for a blog.
Modifying the Schema
Edit the schema file to add a posts table:
// api/db/schema.ts
import { sql } from "drizzle-orm";
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const users = sqliteTable("users", {
id: text("id").primaryKey(),
name: text("name"),
email: text("email").notNull(),
hashedPassword: text("hashed_password"),
salt: text("salt"),
resetToken: text("reset_token"),
resetTokenExpiresAt: integer("reset_token_expires_at"),
createdAt: integer("created_at", { mode: "timestamp" }).default(sql`CURRENT_TIMESTAMP`),
updatedAt: integer("updated_at", { mode: "timestamp" }).default(sql`CURRENT_TIMESTAMP`),
});
// Add a new posts table
export const posts = sqliteTable("posts", {
id: text("id").primaryKey(),
title: text("title").notNull(),
body: text("body").notNull(),
userId: text("user_id").references(() => users.id),
createdAt: integer("created_at", { mode: "timestamp" }).default(sql`CURRENT_TIMESTAMP`),
updatedAt: integer("updated_at", { mode: "timestamp" }).default(sql`CURRENT_TIMESTAMP`),
});
Generating a Migration
After modifying the schema, generate a migration:
bun migrate:new
This will create a new migration file in the drizzle
directory.
Deploy with Migrations
Now that we've modified the schema and generated migrations, let's redeploy our application with the updated database schema:
bun ./alchemy.run
The D1Database resource will automatically apply migrations from the directory we specified earlier (migrationsDir: "drizzle"
).
Local Development
Redwood has integrated development tooling. Run the development server:
bun run dev
This will start both the web and API sides of your Redwood application:
VITE v6.3.2 ready in 2848 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ Debug: http://localhost:5173/__debug
➜ press h + enter to show help
^C%
Tear Down
That's it! You can now tear down the app (if you want to):
bun ./alchemy.run --destroy