Skip to main content
Deploy RedwoodJS applications to Cloudflare Workers with optimized build settings.

Installation

Install the required dependencies:
npm install alchemy @redwoodjs/core @redwoodjs/vite

Configuration

1
Create Worker Entry Point
2
Create a src/worker.tsx file:
3
import { createHandler } from "@redwoodjs/vite/worker";

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const handler = createHandler();
    return handler(request, env, ctx);
  },
};
4
Create Deployment Script
5
Create an alchemy.run.ts file:
6
import alchemy from "alchemy";
import { D1Database, Redwood } from "alchemy/cloudflare";

const app = await alchemy("my-redwood-app");

const database = await D1Database("database", {
  name: `${app.name}-${app.stage}-db`,
});

const website = await Redwood("website", {
  bindings: {
    DB: database,
    DATABASE_URL: `d1://${database.databaseId}`,
  },
});

console.log({
  url: website.url,
});

await app.finalize();
7
Deploy
8
Run your deployment script:
9
npm exec tsx alchemy.run.ts

Configuration Options

Properties

  • bindings: Cloudflare bindings (KV, R2, D1, etc.)
  • build: Build command and environment
    • Default command: rm -rf ./node_modules/.vite && vite build
    • Default env: { RWSDK_DEPLOY: "1" }
  • entrypoint: Worker entrypoint path
    • Default: dist/worker/index.js
  • compatibilityFlags: Cloudflare compatibility flags
    • Default: ["nodejs_compat"]
  • compatibilityDate: Cloudflare compatibility date
    • Default: 2025-08-21
  • wrangler.main: Path to worker source file
    • Default: src/worker.tsx

Build Process

The Redwood resource performs these build steps:
  1. Clears Vite cache (node_modules/.vite)
  2. Runs Vite build with RWSDK_DEPLOY=1
  3. Bundles worker code
  4. Outputs to dist/worker/

Custom Build Command

const website = await Redwood("website", {
  build: {
    command: "vite build --mode production",
    env: {
      RWSDK_DEPLOY: "1",
      NODE_ENV: "production",
    },
  },
});

Accessing Bindings

Access Cloudflare bindings in your RedwoodJS application:

GraphQL Resolvers

import type { QueryResolvers } from "types/graphql";

export const users: QueryResolvers["users"] = async (_, __, { context }) => {
  const db = context.env.DB;
  const result = await db.prepare("SELECT * FROM users").all();
  return result.results;
};

Services

import { context } from "@redwoodjs/api";

export const getUserById = async ({ id }) => {
  const db = context.env.DB;
  const user = await db
    .prepare("SELECT * FROM users WHERE id = ?")
    .bind(id)
    .first();
  return user;
};

Database Integration

Use D1 Database with Prisma:
const database = await D1Database("database", {
  name: `${app.name}-${app.stage}-db`,
});

const website = await Redwood("website", {
  bindings: {
    DB: database,
    DATABASE_URL: `d1://${database.databaseId}`,
  },
});
Configure Prisma for D1:
// schema.prisma
datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

Node.js Compatibility

RedwoodJS automatically enables:
  • nodejs_compat compatibility flag
  • Node.js built-in modules
  • Full RedwoodJS feature set
  • Prisma support

Local Development

Start the RedwoodJS dev server:
npm run dev
The dev server provides:
  • Hot module replacement
  • GraphQL Playground
  • Storybook integration
  • Database migrations

Vite Cache Management

The default build command clears Vite cache to prevent stale builds:
rm -rf ./node_modules/.vite && vite build
Skip cache clearing if needed:
const website = await Redwood("website", {
  build: "vite build",
});

TypeScript Configuration

Define types for Cloudflare bindings:
// api/src/types.ts
import type { D1Database } from "@cloudflare/workers-types";

declare global {
  interface Env {
    DB: D1Database;
    DATABASE_URL: string;
  }
}

Deployment Best Practices

  • Keep dist/ directory in .gitignore
  • Use D1 Database for data persistence
  • Configure DATABASE_URL for Prisma
  • Test migrations locally before deploying
  • Clear Vite cache on build failures

Build docs developers (and LLMs) love