This could be the start of something small
RedwoodSDK is a React framework for building server-side web apps on Cloudflare
From concept to cloud
It begins as a Vite plugin that unlocks SSR, React Server Components, Server Functions, and realtime features.And it ends with you building something awesome!
$ npx create-rwsdk my-project-name
One Response to build them all
Every route is just a function
- Return JSX, stream a response, or upgrade to websockets.
- There’s no special syntax or compiler magic.
- A route is a standard function that takes a Request and returns a Response - or even a <Page />
export default defineApp([
render(Document, [
index(Home),
route("/users", UsersPage),
route("ping", () => new Response(
"pong", { status: 200 }
)),
]),
]);
Built on Standards
- Request and Response follow the native Web API.
- Stream responses, upgrade protocols, debug in DevTools — no wrappers or black boxes.
defineApp([
route("/upload/", async ({ request }) => {
const formData = await request.formData();
const file = formData.get("file") as File;
const r2ObjectKey = `/storage/${file.name}`;
await env.R2.put(r2ObjectKey, file.stream(), {
httpMetadata: {
contentType: file.type,
},
});
return new Response(JSON.stringify({ key: r2ObjectKey }), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
}),
]);
Co-Locate Logic and UI
- Define your API and UI in the same place.
- Keep your JSON and JSX responses together, scoped to a single router.
- One file, one mental model.
const authRoutes = [
route("/login", Login),
route("/account", [
async ({ ctx, request }) => {
if (!ctx.user) {
const headers = new Headers();
await sessions.remove(request, headers);
headers.set("Location", "/auth/login");
return new Response(null, {
status: 302,
headers,
});
}
},
AccountPage
]),
];
export default authRoutes;
Interruptors
- Shape the request flow before it hits your route.
- Interruptors let you intercept requests, check auth, redirect, or halt the response, on a per route basis, with full access to the environment and context.
function isAuthenticated({ request, ctx }) {
if (!ctx.user) {
return new Response("Unauthorized", { status: 401 })
}
}
defineApp([
route("/blog/:slug/edit", [isAuthenticated, EditBlogPage]);
])
Middleware That Matters
- Run logic before and after your routes.
- Middleware is part of the request/response flow — ideal for injecting headers, setting up context, or streaming from the edge.
defineApp([
sessionMiddleware,
async function getUserMiddleware({ request, ctx }) {
if (ctx.session.userId) {
ctx.user = await db.user.find({ where: { id: ctx.session.userId } });
}
},
route("/hello", [
function ({ ctx }) {
if (!ctx.user) {
return new Response("Unauthorized", { status: 401 });
}
},
function ({ ctx }) {
return new Response(`Hello ${ctx.user.username}!`);
},
]),
]);
Total Control Over the Document
- Render the HTML document yourself — no hidden magic.
- You choose what goes over the wire. Turn client-side React on or off.
- Inject headers, preload tags, inline styles, or raw HTML.
- You’re in control of the entire response, from status code to closing tag.
import { Document } from "@/pages/Document";
import { NoJSDocument } from "@/pages/NoJSDocument";
import { HomePage } from "@/pages/HomePage";
export default defineApp([
render(Document, [route("/", HomePage)]),
render(NoJSDocument, [
route("/no-js", () => new Response(
"No Javascript injected in this Document, just plain HTML",
{ status: 200 })
)
])
]);
React Server Components - as they're meant to be
React Server Components are a powerful way to build server-side web apps on Cloudflare.
Everything is server-first by default. Your components run on the server where they belong, streaming HTML straight to the browser. When you need interactivity, just mark a component with use client. It's the same mental model you'd use anywhere else—only now it runs on the edge.
There's no need to wrestle with bundlers, patch frameworks, or manually split code between server and client. RedwoodSDK treats React's directives as first-class citizens and integrates them seamlessly with Vite and Cloudflare Workers. The result is lightning-fast time-to-interactive, zero boilerplate, and a dev environment that mirrors production—without any extra setup.
Concept to Cloudflare
RedwoodSDK is built for Cloudflare from the first line of code.
No adapters, no shims. What runs locally is what runs in production. Development uses Miniflare to emulate Cloudflare Workers with uncanny accuracy. You're not faking the edge. You're building on it. No config drift. No "it worked on my machine." Just a clean path from idea to deploy.
PS… Built for Builders
RedwoodSDK is for people who write software they own.
It's built on browser standards, not vendor abstractions—just native Web APIs and predictable behavior from request to response.
Bring your own tools. Use realtime out of the box. Run locally on Cloudflare's stack with zero config—D1, R2, Queues, Workers AI, and more.
No wrappers.No black boxes.Just flow.
Be the first to know
Get a summary of what we've shipped, articles we've written, and upcoming events straight to your inbox, at most once every two weeks.