Peter Pistorius
Creator
2025-04-23
Most frameworks give you a fixed HTML document: a <!DOCTYPE html>
page with a <head>
, a <body>
, and a root div for React to hydrate into. You might be able to tweak the title or inject a meta tag—but the structure? That’s locked down.
RedwoodSDK takes a different approach.
In Redwood, every route can define its own document. Not just the content. The document. That means you choose the structure, the scripts, and even whether React runs in the browser at all.
Here’s what that looks like:
// src/app/Document.tsx
export const Document: React.FC<{ children: React.ReactNode }> = ({
children,
}) => (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My App</title>
<link rel="preload" href="/src/client.tsx" as="script" />
</head>
<body>
<div id="root">{children}</div>
<script src="/src/client.tsx"></script>
</body>
</html>
);
Simple, explicit, and powerful.
Let’s break it down:
<script>
tag. You’re shipping static HTML.<script>
to hydrate the page.Document
component for each one.If you don’t include hydration, React is used purely as a templating language—it renders HTML on the server, and that’s it. That’s perfect for marketing pages, blog posts, docs—things that don’t need JavaScript at all.
Want to add React Server Components that personalize content server-side? You can.
Want to hydrate a dynamic dashboard? Just include the right script.
Want to replace the <script>
with a socket-based hydration strategy? Nothing’s stopping you.
Because you define the document per route, you can build:
/
: a static homepage with zero JavaScript/app/user/login
: an interactive form with client-side validation/app/dashboard
: a realtime UI hydrated over websockets// src/worker.tsx
import { defineApp } from 'rwsdk/worker'
import { render, route, prefix } from 'rwsdk/router'
import { StaticDocument } from '@/app/StaticDocument.tsx'
import { StandardDocument } from '@/app/StandardDocument.tsx'
import { RealtimeDocument } from '@/app/RealtimeDocument.tsx'
export default defineApp([
render(StaticDocument, [
route('/', HomePage),
prefix('/blog', blogRoutes),
]),
render(StandardDocument, [
prefix('/app/user', userRoutes),
])
render(RealtimeDocument, [
prefix('/app/dashboard', dashboardRoutes),
])
])
All in the same app. All running in the same Cloudflare worker.
That’s not common. Most frameworks treat the document as a global, one-size-fits-all concern. RedwoodSDK treats it as just another component—one you control.
RedwoodSDK is built for Cloudflare, where the edge is the server. That means low-latency rendering, streaming responses, and precise control over what gets sent down the wire.
We don’t want to hide that. We want to hand it to you.
This model encourages you to think like a browser. To optimize where it matters. To ship the right payload for the job.
It’s personal software thinking applied to web apps.
RedwoodSDK gives you full control over your HTML document, per route.
Document
componentIt’s HTML-first, React-powered, and totally under your control.