### Build and Start Waku Example
Source: https://github.com/wakujs/waku/blob/main/CONTRIBUTING.md
Builds and then starts a specific Waku example. Use this to see the example in a production-like state.
```shell
pnpm -F 01_template build
pnpm -F 01_template start
```
--------------------------------
### Install Dependencies and Run Development Server
Source: https://github.com/wakujs/waku/blob/main/docs/guides/getting-started.mdx
After creating the project, navigate into the project directory, install the necessary dependencies, and start the development server to view your app.
```bash
cd waku-project
npm install
npm run dev
```
--------------------------------
### Run Waku Example in Development Mode
Source: https://github.com/wakujs/waku/blob/main/CONTRIBUTING.md
Starts a specific Waku example (e.g., 01_template) in development mode. This is useful for iterative development and testing of examples.
```shell
pnpm -F 01_template dev
```
--------------------------------
### Jotai Provider Setup
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-002.mdx
Set up Jotai's `Provider` component to manage global state. This example creates a store and wraps the application's children with the provider.
```tsx
'use client';
import { createStore, Provider } from 'jotai';
const store = createStore();
export const Providers = ({ children }) => {
return {children};
};
```
--------------------------------
### Install Minimal Client Runtime with `Root`
Source: https://github.com/wakujs/waku/blob/main/docs/guides/minimal-api.mdx
The `Root` component is used to install the minimal client runtime for Waku.
```typescript
import { Root } from "waku/minimal/client";
function App() {
return (
{/* Client-side content */}
);
}
```
--------------------------------
### Route Grouping Example Directory Structure
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-010.mdx
Illustrates how to structure directories using parentheses to create route groups for shared layouts.
```bash
├── (some-group)
│ ├── _layout.tsx
│ ├── about.tsx
│ └── other-page.tsx
└── index.tsx
```
--------------------------------
### Global Stylesheet Example
Source: https://github.com/wakujs/waku/blob/main/README.md
A basic example of a global stylesheet, demonstrating the use of CSS imports. This file can contain any valid CSS, including framework-specific directives.
```css
/* ./src/styles.css */
@import 'tailwindcss';
```
--------------------------------
### Install Serverless Framework Plugin
Source: https://github.com/wakujs/waku/blob/main/docs/guides/aws-lambda.mdx
Add the `serverless-scriptable-plugin` to your project's development dependencies using pnpm.
```sh
pnpm add -D serverless-scriptable-plugin
```
--------------------------------
### Install Dependencies with PNPM
Source: https://github.com/wakujs/waku/blob/main/CONTRIBUTING.md
Installs project dependencies using PNPM. Ensure Corepack is enabled first.
```shell
corepack enable
pnpm install
```
--------------------------------
### Compile Waku Project
Source: https://github.com/wakujs/waku/blob/main/CONTRIBUTING.md
Builds the Waku project. This command must be run before attempting to run examples.
```shell
pnpm run compile
```
--------------------------------
### Install Dependencies for React Compiler
Source: https://github.com/wakujs/waku/blob/main/docs/guides/react-compiler.mdx
Use this command to install the necessary Vite React plugin, React Compiler Babel plugin, and Rolldown Babel plugin when upgrading an existing Waku project.
```bash
npm install -D @vitejs/plugin-react babel-plugin-react-compiler @rolldown/plugin-babel
```
--------------------------------
### Platform Environment Bindings Example
Source: https://github.com/wakujs/waku/blob/main/docs/guides/adapter-authoring.mdx
Demonstrates how to use `setAllEnv` to integrate platform-specific environment bindings into Waku's request processing.
```typescript
export default createServerEntryAdapter(
({ processRequest, processBuild, setAllEnv }) => {
return {
fetch: async (req: Request, env: Record) => {
setAllEnv(env);
const res = await processRequest(req);
return res || new Response('Not Found', { status: 404 });
},
build: processBuild,
};
},
);
```
--------------------------------
### Async Server Component Example
Source: https://github.com/wakujs/waku/blob/main/docs/guides/getting-started.mdx
This is an example of an async server component. It allows for data fetching directly on the server, which can improve client bundle size and enable server-side logic.
```tsx
export default async function HomePage() {
const data = await getData();
// ...rest of the file
}
```
--------------------------------
### Netlify Adapter for Pure SSG
Source: https://github.com/wakujs/waku/blob/main/README.md
Configure the Netlify adapter for Waku to deploy a purely static site. This setup avoids deploying serverless functions.
```ts
import { fsRouter } from 'waku';
import adapter from 'waku/adapters/netlify';
export default adapter(fsRouter(import.meta.glob('./pages/**/*.{tsx,ts}')), {
static: true,
});
```
--------------------------------
### Create Waku Project with Cloudflare Template
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-0016.mdx
Use this command to initialize a new Waku project pre-configured for Cloudflare Workers. It installs `@hiogawa/node-loader-cloudflare` automatically.
```sh
npm create waku@latest -- --template 07_cloudflare
```
--------------------------------
### Create Home Page with Dynamic Rendering
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-003.mdx
Example of a home page component that fetches data and is configured for dynamic rendering at request time.
```tsx
// ./src/pages/index.tsx
// Create home page
export default async function HomePage() {
const data = await getData();
return (
<>
{data.title}
{data.content}
>
);
}
const getData = async () => {
/* ... */
};
export const getConfig = async () => {
return {
render: 'dynamic',
};
};
```
--------------------------------
### Install Cloudflare Vite Plugin and Wrangler
Source: https://github.com/wakujs/waku/blob/main/docs/guides/cloudflare.mdx
Install the necessary development dependencies for integrating Waku with Cloudflare Workers.
```sh
npm install --save-dev @cloudflare/vite-plugin wrangler
```
--------------------------------
### Static API Example
Source: https://github.com/wakujs/waku/blob/main/docs/create-pages.mdx
Defines a static API endpoint for RSS feed generation.
```APIDOC
## GET /rss.xml
### Description
Provides a static RSS feed.
### Method
GET
### Endpoint
/rss.xml
### Request Example
(No request body for GET)
### Response
#### Success Response (200)
- **Content-Type**: application/rss+xml
- **Body**: RSS XML content
### Response Example
```xml
```
```
--------------------------------
### Build and Run Docker Container
Source: https://github.com/wakujs/waku/blob/main/docs/guides/docker.mdx
Command to build the Docker image and start the Waku application container using Docker Compose.
```sh
docker compose up --build
```
--------------------------------
### Static Slice Creation
Source: https://github.com/wakujs/waku/blob/main/docs/create-pages.mdx
Example of creating a reusable static slice component.
```APIDOC
## createSlice({ render: 'static', id: 'one', component: SliceOne })
### Description
Creates a static slice with the ID 'one' using the `SliceOne` component.
### Parameters
- **render**: 'static'
- **id**: 'one'
- **component**: `SliceOne` (imported component)
```
--------------------------------
### Path Specification Examples
Source: https://github.com/wakujs/waku/blob/main/docs/guides/custom-router.mdx
Illustrates different path specifications for Waku routes, including literal segments, groups for dynamic slugs, and wildcards for catch-all paths.
```ts
// /
[];
```
```ts
// /about
[{ type: 'literal', name: 'about' }];
```
```ts
// /posts/[slug]
[
{ type: 'literal', name: 'posts' },
{ type: 'group', name: 'slug' },
];
```
```ts
// /files/[...path]
[
{ type: 'literal', name: 'files' },
{ type: 'wildcard', name: 'path' },
];
```
--------------------------------
### Dockerfile for Waku App
Source: https://github.com/wakujs/waku/blob/main/docs/guides/docker.mdx
This Dockerfile uses a multi-stage build to create a production-ready Docker image for a Waku application. The builder stage installs dependencies and builds the app, while the runner stage installs only production dependencies and copies the build output.
```dockerfile
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
EXPOSE 8080
CMD ["npm", "run", "start"]
```
--------------------------------
### Fetch Blog Article Data in Waku
Source: https://github.com/wakujs/waku/blob/main/README.md
Fetch and render blog articles using server components. This example demonstrates fetching article content and metadata, and configuring static path generation.
```tsx
// ./src/pages/blog/[slug].tsx
import type { PageProps } from 'waku/router';
import { MDX } from '../../components/mdx';
import { getArticle, getStaticPaths } from '../../lib/blog';
export default async function BlogArticlePage({
slug,
}: PageProps<'/blog/[slug]'>) {
const article = await getArticle(slug);
return (
<>
{article.frontmatter.title}
{article.frontmatter.title}
{article.content}
>
);
}
export const getConfig = async () => {
const staticPaths = await getStaticPaths();
return {
render: 'static',
staticPaths,
} as const;
};
```
--------------------------------
### Docker Compose Up Command
Source: https://context7.com/wakujs/waku/llms.txt
Command to build and start the Waku application defined in docker-compose.yml. The application will be accessible at http://localhost:8080.
```sh
docker compose up --build
# App available at http://localhost:8080
```
--------------------------------
### Static API with Dynamic Segment Example
Source: https://github.com/wakujs/waku/blob/main/docs/create-pages.mdx
Defines a static API with a dynamic segment that can be pre-rendered for specific paths.
```APIDOC
## GET /feeds/[category]
### Description
Provides static feeds for different categories.
### Method
GET
### Endpoint
/feeds/:category
### Parameters
#### Path Parameters
- **category** (string) - Required - The category of the feed.
### Request Example
(No request body for GET)
### Response
#### Success Response (200)
- **Body**: Text indicating the feed for the specified category.
### Response Example
```
Feed for news
```
```
--------------------------------
### Vercel Adapter for Pure SSG
Source: https://github.com/wakujs/waku/blob/main/README.md
Configure the Vercel adapter for Waku to deploy a purely static site. This setup avoids deploying serverless functions.
```ts
import { fsRouter } from 'waku';
import adapter from 'waku/adapters/vercel';
export default adapter(fsRouter(import.meta.glob('./pages/**/*.{tsx,ts}')), {
static: true,
});
```
--------------------------------
### Dynamic Slice Creation
Source: https://github.com/wakujs/waku/blob/main/docs/create-pages.mdx
Example of creating a reusable dynamic slice component.
```APIDOC
## createSlice({ render: 'dynamic', id: 'two', component: SliceTwo })
### Description
Creates a dynamic slice with the ID 'two' using the `SliceTwo` component.
### Parameters
- **render**: 'dynamic'
- **id**: 'two'
- **component**: `SliceTwo` (imported component)
```
--------------------------------
### Dynamic API Example
Source: https://github.com/wakujs/waku/blob/main/docs/create-pages.mdx
Defines a dynamic API endpoint that accepts a user ID parameter.
```APIDOC
## API /api/users/[id]
### Description
Handles dynamic API requests for user data based on ID.
### Method
GET
### Endpoint
/api/users/:id
### Parameters
#### Path Parameters
- **id** (string) - Required - The ID of the user.
### Request Example
(No request body for GET)
### Response
#### Success Response (200)
- **id** (string) - The ID of the user.
### Response Example
```json
{
"id": "123"
}
```
```
--------------------------------
### Configure Waku Project with defineConfig
Source: https://context7.com/wakujs/waku/llms.txt
Customize Waku project settings like base path, source/output directories, and Vite configurations using defineConfig. This example includes Tailwind CSS and React plugins.
```typescript
import babel from '@rolldown/plugin-babel';
import tailwindcss from '@tailwindcss/vite';
import react, { reactCompilerPreset } from '@vitejs/plugin-react';
import { defineConfig } from 'waku/config';
export default defineConfig({
// Base path for all HTTP routes (default: '/')
basePath: '/',
// Source directory (default: 'src')
srcDir: 'src',
// Build output directory (default: 'dist')
distDir: 'dist',
// Private server-only files directory (default: 'private')
privateDir: 'private',
// RSC request base path (default: 'RSC')
rscBase: 'RSC',
// Override adapter (e.g. for Cloudflare without env vars)
// unstable_adapter: 'waku/adapters/cloudflare',
// Vite configuration — plugins, aliases, resolve options, etc.
vite: {
plugins: [
tailwindcss(),
react(),
babel({ presets: [reactCompilerPreset()] }),
],
resolve: {
// Prevent duplicate React in monorepos
dedupe: ['react', 'react-dom'],
},
},
});
```
--------------------------------
### Root Layout with Header and Footer
Source: https://github.com/wakujs/waku/blob/main/README.md
An example of a root layout that includes global components like Header and Footer, alongside children content. It is configured for static rendering.
```tsx
// ./src/pages/_layout.tsx
import '../styles.css';
import { Providers } from '../components/providers';
import { Header } from '../components/header';
import { Footer } from '../components/footer';
// Create root layout
export default async function RootLayout({ children }) {
return (
{children}
);
}
export const getConfig = async () => {
return {
render: 'static',
} as const;
};
```
--------------------------------
### Progressive Form with Server Action
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-007.mdx
This example demonstrates a progressive form using a server action. The form can be submitted and processed by the server action even without client-side JavaScript.
```jsx
async function submitForm(formData) {
'use server';
await fetch('https://api.example.com/submit', {
method: 'POST',
body: JSON.stringify(Object.fromEntries(formData)),
});
}
const ServerForm = () => {
return (
);
};
```
--------------------------------
### Set Custom Headers for Static Assets (_headers file)
Source: https://github.com/wakujs/waku/blob/main/docs/guides/cloudflare.mdx
Use a `_headers` file in the `public` folder to define custom headers for static assets. This example prevents indexing of RSC files by search engines.
```txt
/RSC/\n X-Robots-Tag: noindex
```
--------------------------------
### Import Preview Server Builder
Source: https://github.com/wakujs/waku/blob/main/docs/guides/adapter-authoring.mdx
Import the `unstable_startPreviewServer` function to enable Waku execution within a local runtime during the build process.
```typescript
import { unstable_startPreviewServer as startPreviewServer } from 'waku/adapter-builders';
```
--------------------------------
### Import Server-Safe Atom in Server Page
Source: https://github.com/wakujs/waku/blob/main/docs/guides/state-across-client-server.mdx
Server code can import and use atoms marked with `allowServer` from client modules. This example shows how to get the initial state of the atom using `getStore`.
```tsx
// src/pages/index.tsx
import { getStore } from 'waku-jotai/router';
import { Counter, countAtom } from '../components/counter';
export default async function Page() {
const store = await getStore();
return (
<>
Initial count: {store.get(countAtom)}
>
);
}
```
--------------------------------
### Bootstrap a New Waku Project
Source: https://context7.com/wakujs/waku/llms.txt
Use the create command to scaffold a new Waku project. You can specify a template for specific environments like Cloudflare Workers. After creation, install dependencies and run development or production commands.
```bash
npm create waku@latest
# or with a specific template (e.g. Cloudflare Workers)
npm create waku@latest -- --template 07_cloudflare
cd waku-project
npm install
npm run dev # dev server at http://localhost:3000
npm run build # production build
npm run start # serve the production build
```
--------------------------------
### Access Cloudflare Bindings and Request Context
Source: https://github.com/wakujs/waku/blob/main/docs/guides/cloudflare.mdx
Import `env` and `waitUntil` from `cloudflare:workers` to access Cloudflare bindings. Use `unstable_getContext` from `waku/server` to get the request context. This example demonstrates fetching user data from a D1 database using environment bindings.
```typescript
import { env, waitUntil } from 'cloudflare:workers'; // eslint-disable-line import/no-unresolved
import { unstable_getContext as getContext } from 'waku/server';
const getData = async () => {
const { req } = getContext();
waitUntil(
new Promise((resolve) => {
console.log('Waiting for 5 seconds');
setTimeout(() => {
console.log('OK, done waiting');
resolve();
}, 5000);
}),
);
const url = new URL(req.url);
const userId = url.searchParams.get('userId');
if (!userId) {
return null;
}
const { results } = await env.DB.prepare('SELECT * FROM user WHERE id = ?')
.bind(userId)
.all();
return results;
};
```
--------------------------------
### Waku Client Entry Point
Source: https://github.com/wakujs/waku/blob/main/docs/guides/minimal-api.mdx
Sets up the client-side React root and hydrates the application. Ensures the root element is wrapped in `` and uses `` for content.
```tsx
import { StrictMode } from 'react';
import { createRoot, hydrateRoot } from 'react-dom/client';
import { Root, Slot } from 'waku/minimal/client';
const rootElement = (
);
if ((globalThis as any).__WAKU_HYDRATE__) {
hydrateRoot(document, rootElement);
} else {
createRoot(document).render(rootElement);
}
```
--------------------------------
### Creating an API Route (POST Example)
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-009.mdx
Demonstrates how to create a POST API route in Waku by exporting an async function named POST in a file within the `./src/pages/api` directory. The function handles a JSON request body and returns a standard Response object.
```APIDOC
## POST /api/contact
### Description
Handles POST requests to the /api/contact endpoint. It expects a JSON body with a 'message' field, processes it, and returns a success or error response.
### Method
POST
### Endpoint
/api/contact
### Request Body
- **message** (string) - Required - The message content to be sent.
### Request Example
```json
{
"message": "Hello from the contact form!"
}
```
### Response
#### Success Response (200)
- **message** (string) - Indicates successful processing of the request.
#### Error Response (400)
- **message** (string) - Indicates an invalid request body (e.g., missing 'message' field).
#### Error Response (500)
- **message** (string) - Indicates a server-side error during email processing.
### Response Example (Success)
```json
{
"message": "Success"
}
```
### Response Example (Error)
```json
{
"message": "Invalid"
}
```
```
--------------------------------
### Waku Client Router Setup
Source: https://github.com/wakujs/waku/blob/main/docs/guides/custom-router.mdx
Configure the Waku router client for your application. This setup is standard for client-side routing and hydration.
```tsx
// src/waku.client.tsx
import { StrictMode } from 'react';
import { createRoot, hydrateRoot } from 'react-dom/client';
import { unstable_defaultRootOptions as defaultRootOptions } from 'waku/client';
import { ErrorBoundary, Router } from 'waku/router/client';
const rootElement = (
);
if ((globalThis as any).__WAKU_HYDRATE__) {
hydrateRoot(document, rootElement, defaultRootOptions);
} else {
createRoot(document, defaultRootOptions).render(rootElement);
}
```
--------------------------------
### Bootstrap AWS CDK
Source: https://github.com/wakujs/waku/blob/main/docs/guides/aws-lambda.mdx
Initializes the AWS CDK environment for deployment.
```sh
pnpm cdk bootstrap
```
--------------------------------
### Add CDK Packages
Source: https://github.com/wakujs/waku/blob/main/docs/guides/aws-lambda.mdx
Installs necessary AWS CDK packages using pnpm.
```sh
pnpm add -D aws-cdk
pnpm add aws-cdk-lib constructs
```
--------------------------------
### Scaffold a New Waku Project
Source: https://github.com/wakujs/waku/blob/main/docs/guides/getting-started.mdx
Use this command to create a new Waku project. Follow the CLI prompts for configuration. The default project name is 'waku-project'.
```bash
npm create waku@latest
```
--------------------------------
### Configuring Static Host
Source: https://github.com/wakujs/waku/blob/main/docs/guides/static-deployments.mdx
For plain static hosts, configure the publish directory to `dist/public`. Ensure the host serves files as they exist on disk and avoids a single-page-app fallback for non-emitted routes.
```txt
dist/public
```
--------------------------------
### Get Request Headers
Source: https://github.com/wakujs/waku/blob/main/docs/guides/request-context.mdx
Use `unstable_getHeaders` to retrieve request headers for the current request. The returned object is a snapshot of these headers.
```tsx
import { unstable_getHeaders as getHeaders } from 'waku/server';
export default function Page() {
const headers = getHeaders();
const userAgent = headers['user-agent'] || 'unknown';
return
User agent: {userAgent}
;
}
```
--------------------------------
### Minimal Fetch Adapter
Source: https://github.com/wakujs/waku/blob/main/docs/guides/adapter-authoring.mdx
A basic adapter that handles runtime requests and allows Waku's build process to run. Use this for learning the adapter contract.
```typescript
// my-waku-adapter.ts
import { unstable_createServerEntryAdapter as createServerEntryAdapter } from 'waku/adapter-builders';
export default createServerEntryAdapter(({ processRequest, processBuild }) => {
return {
fetch: async (req: Request) => {
const res = await processRequest(req);
return res || new Response('Not Found', { status: 404 });
},
build: processBuild,
};
});
```
```typescript
import { fsRouter } from 'waku';
import adapter from './my-waku-adapter';
export default adapter(
fsRouter(import.meta.glob('./**/*.{tsx,ts}', { base: './pages' })),
);
```
--------------------------------
### Custom Vite Configuration with Environments
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-011.mdx
Illustrates how to configure Vite environments (client, ssr, rsc) and add custom plugins in `waku.config.ts`.
```typescript
import { defineConfig } from 'waku/config';
export default defineConfig({
vite: {
environments: {
// environment-specific configurations.
client: {
build: {
// disable client assets minification
minify: false,
},
},
ssr: {
optimizeeDeps: {
include: [
// handle cjs package for SSR
],
},
},
rsc: {
// ...
},
},
plugins: [
// custom plugins
{
name: 'my-custom-plugin',
transform(code, id) {
// e.g. transform only on `rsc` environment
if (this.environment.name === 'rsc') {
// ...
}
},
},
],
},
});
```
--------------------------------
### Nested Layout for Blog Section
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-003.mdx
Applies a specific layout to a section of the application, such as the blog. This example adds a sidebar to all blog-related pages.
```tsx
// ./src/pages/blog/_layout.tsx
import { Sidebar } from '../../components/sidebar';
// Create blog layout
export default async function BlogLayout({ children }) {
return (
{children}
);
}
export const getConfig = async () => {
return {
render: 'static',
};
};
```
--------------------------------
### Create Blog Index Page with Static Rendering
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-003.mdx
Component for the main blog index page, configured for static rendering.
```tsx
// ./src/pages/blog.tsx
// Create blog index page
export default async function BlogIndexPage() {
return <>{/* ...*/}>;
}
export const getConfig = async () => {
return {
render: 'static',
};
};
```
--------------------------------
### Platform Default Exports Example
Source: https://github.com/wakujs/waku/blob/main/docs/guides/adapter-authoring.mdx
Shows how to return a platform-specific `defaultExport` to accommodate runtimes needing custom shapes, such as additional handlers.
```typescript
export default createServerEntryAdapter(
(
{ processRequest, processBuild, setAllEnv },
options?: { handlers?: Record },
) => {
const fetch = async (req: Request, env: Record) => {
setAllEnv(env);
const res = await processRequest(req);
return res || new Response('Not Found', { status: 404 });
};
return {
fetch,
build: processBuild,
defaultExport: {
...options?.handlers,
fetch,
},
};
},
);
```
--------------------------------
### Initialize CDK Project
Source: https://github.com/wakujs/waku/blob/main/docs/guides/aws-lambda.mdx
Initializes a new AWS CDK project with TypeScript and sets up the application entry point.
```sh
mkdir cdk && cd "$_"
pnpx cdk init app -l typescript --generate-only
cd ..
cp cdk/cdk.json .
```
--------------------------------
### Configure Waku Server for Cloudflare Adapter
Source: https://github.com/wakujs/waku/blob/main/docs/guides/cloudflare.mdx
Set up the Waku server entry point to use the Cloudflare adapter for routing.
```typescript
// ./src/waku.server.tsx
import { fsRouter } from 'waku';
import adapter from 'waku/adapters/cloudflare';
export default adapter(fsRouter(import.meta.glob('./pages/**/*.{tsx,ts}')));
```
--------------------------------
### Slice Configuration Example
Source: https://github.com/wakujs/waku/blob/main/docs/guides/custom-router.mdx
Defines a server-rendered fragment with a static ID. This slice can be included in route payloads or requested later by the client.
```tsx
{
type: 'slice',
id: 'cart-summary',
isStatic: false,
renderer: async () => ,
}
```
--------------------------------
### Client Component with State and Transitions
Source: https://context7.com/wakujs/waku/llms.txt
Create client components by marking files with `'use client'`. These components are hydrated in the browser and can manage local state and transitions.
```tsx
// src/components/counter.tsx
'use client';
import { useState, useTransition } from 'react';
export const Counter = ({ initial = 0 }: { initial?: number }) => {
const [count, setCount] = useState(initial);
const [isPending, startTransition] = useTransition();
const increment = () =>
startTransition(() => setCount((c) => c + 1));
return (
);
};
// src/pages/index.tsx — server component composing client component
import { Counter } from '../components/counter';
export default async function HomePage() {
const initial = await fetchInitialCount(); // server-only
return ;
}
const fetchInitialCount = async () => 42;
export const getConfig = async () => ({ render: 'static' } as const);
```
--------------------------------
### Optional Docker HEALTHCHECK
Source: https://github.com/wakujs/waku/blob/main/docs/guides/docker.mdx
An example health check command to add to the Dockerfile. This command periodically checks if the application is responsive on port 8080.
```dockerfile
HEALTHCHECK --interval=30s CMD wget -qO- http://localhost:8080 || exit 1
```
--------------------------------
### Bun Adapter Configuration
Source: https://github.com/wakujs/waku/blob/main/README.md
Configure the Bun adapter for Waku. This is an experimental adapter for deploying to Bun environments.
```ts
import { fsRouter } from 'waku';
import adapter from 'waku/adapters/bun';
export default adapter(fsRouter(import.meta.glob('./pages/**/*.{tsx,ts}')));
```
--------------------------------
### Client Entry Point for Waku
Source: https://github.com/wakujs/waku/blob/main/docs/create-pages.mdx
The default client entry file for Waku applications. It handles the initial rendering and hydration of the application using React DOM's `createRoot` or `hydrateRoot`.
```tsx
import { Component, StrictMode } from 'react';
import { createRoot, hydrateRoot } from 'react-dom/client';
import { Router } from 'waku/router/client';
const rootElement = (
);
if (globalThis.__WAKU_HYDRATE__) {
hydrateRoot(document, rootElement);
} else {
createRoot(document).render(rootElement);
}
```
--------------------------------
### Traditional Client-Side Form Handling
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-007.mdx
This example shows a typical client-side form submission using React. It requires JavaScript to be enabled for the form to be processed.
```jsx
'use client';
const ClientForm = () => {
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
await fetch('/api/submit', {
method: 'POST',
body: JSON.stringify(Object.fromEntries(formData)),
});
};
return (
);
};
```
--------------------------------
### Redirects in Vercel
Source: https://github.com/wakujs/waku/blob/main/docs/guides/redirect-maps.mdx
Configure redirects for Vercel deployments using the `vercel.json` file. This example shows how to set up permanent redirects for both browser and RSC paths.
```json
{
"redirects": [
{ "source": "/old", "destination": "/new", "permanent": true },
{
"source": "/RSC/R/old.txt",
"destination": "/RSC/R/new.txt",
"permanent": true
}
]
}
```
--------------------------------
### Create Static Blog Article Page with Static Paths
Source: https://github.com/wakujs/waku/blob/main/README.md
Defines a static blog article page that uses predefined static paths. The `slug` prop is automatically provided.
```tsx
// ./src/pages/blog/[slug].tsx
import type { PageProps } from 'waku/router';
// Create blog article pages
export default async function BlogArticlePage({
slug,
}: PageProps<'/blog/[slug]'>) {
const data = await getData(slug);
return <>{/* ...*/}>;
}
const getData = async (slug) => {
/* ... */
};
export const getConfig = async () => {
return {
render: 'static',
staticPaths: ['introducing-waku', 'introducing-pages-router'],
} as const;
};
```
--------------------------------
### Create Root Layout and Home Page
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-002.mdx
Define a static root layout and a dynamic home page using createPages. Layout components must accept a 'children' prop.
```tsx
import { createPages } from 'waku';
import { RootLayout } from './templates/root-layout';
import { HomePage } from './templates/home-page';
export default createPages(async ({ createPage, createLayout }) => {
// Create root layout
createLayout({
render: 'static',
path: '/',
component: RootLayout,
});
// Create home page
createPage({
render: 'dynamic',
path: '/',
component: HomePage,
});
});
```
--------------------------------
### Use useRefetch for Dynamic Data Fetching
Source: https://github.com/wakujs/waku/blob/main/docs/guides/minimal-api.mdx
Example of using the useRefetch hook within a React component to trigger a server-side data refetch on a button click.
```tsx
import { useTransition } from 'react';
import { useRefetch } from 'waku/minimal/client';
const Counter = () => {
const [isPending, startTransition] = useTransition();
const refetch = useRefetch();
const handleClick = (count: number) => {
startTransition(async () => {
await refetch('InnerApp=' + count);
});
};
return (
);
};
```
--------------------------------
### Handle Custom API Endpoint
Source: https://github.com/wakujs/waku/blob/main/docs/guides/minimal-api.mdx
Create custom API endpoints for 'custom' input types. This example shows a simple '/api/hello' endpoint returning 'world'.
```tsx
if (input.type === 'custom' && input.pathname === '/api/hello') {
return new Response('world');
}
```
--------------------------------
### Page Parts Directory Structure
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-010.mdx
Example file structure for a route using Page Parts, where files prefixed with '_part' combine to form the page content.
```bash
pages
├── _layout.tsx
├── foo
│ ├── _part-banana.tsx # these combine to be the children for /foo
│ ├── _part-orange.tsx
│ └── _part-cherry.tsx
└── index.tsx # / route
```
--------------------------------
### Create Blog Article Page with Static Paths
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-003.mdx
Component for individual blog articles using a segment route. Includes static paths configuration for build-time rendering.
```tsx
// ./src/pages/blog/[slug].tsx
// Create blog article pages
export default async function BlogArticlePage({ slug }) {
const data = await getData(slug);
return <>{/* ...*/}>;
}
const getData = async (slug) => {
/* ... */
};
export const getConfig = async () => {
return {
render: 'static',
staticPaths: ['introducing-waku', 'introducing-pages-router'],
};
};
```
--------------------------------
### Page Parts Component Tree Example
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-010.mdx
Shows a conceptual component tree for a page utilizing Page Parts, allowing a mix of static and dynamic components.
```tsx
// ordering is flexible here
```
--------------------------------
### Deno Deploy Adapter Configuration
Source: https://github.com/wakujs/waku/blob/main/README.md
Configure the Deno Deploy adapter for Waku. This is an experimental adapter for deploying to Deno Deploy.
```ts
import { fsRouter } from 'waku';
import adapter from 'waku/adapters/deno';
export default adapter(fsRouter(import.meta.glob('./pages/**/*.{tsx,ts}')));
```
--------------------------------
### Shared Component Example
Source: https://github.com/wakujs/waku/blob/main/README.md
Shared components can be imported into either server or client components without affecting the server-client boundary, provided they adhere to the rules for both component types.
```tsx
// shared component
export const Headline = ({ children }) => {
return
{children}
;
};
```
--------------------------------
### Migrate createPages with Default Adapter
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-014.mdx
Update your `server-entry.tsx` to use the default adapter when migrating from previous versions of Waku.
```diff
import { createPages } from 'waku';
+ import adapter from 'waku/adapters/default';
- export default createPages(...);
+ export default adapter(createPages(...));
```
--------------------------------
### Create Single Route Pages
Source: https://github.com/wakujs/waku/blob/main/docs/create-pages.mdx
Define individual pages with specific paths using `createPage`. This example shows how to create an 'about' page and a 'blog' index page.
```tsx
// ./src/waku.server.tsx
import { createPages } from 'waku';
import adapter from 'waku/adapters/default';
import { AboutPage } from './templates/about-page';
import { BlogIndexPage } from './templates/blog-index-page';
const pages = createPages(async ({ createPage }) => [
// Create about page
createPage({
render: 'static',
path: '/about',
component: AboutPage,
}),
// Create blog index page
createPage({
render: 'static',
path: '/blog',
component: BlogIndexPage,
}),
]);
export default adapter(pages);
```
--------------------------------
### Define a Server Action
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-004.mdx
Server actions are defined in server files and can be imported and used in client components. This example shows a basic server action to send a message.
```tsx
// ./src/actions/send-message.ts
'use server';
import db from 'some-db';
export async function sendMessage(formData: FormData) {
const message = formData.get('message');
await db.messages.create(message);
}
```
--------------------------------
### Define Static Home Page with Data Fetching
Source: https://context7.com/wakujs/waku/llms.txt
Create a static home page by exporting a default React component and a `getConfig` function that returns `{ render: 'static' }`. This example demonstrates fetching data asynchronously within the component.
```tsx
// src/pages/index.tsx — static home page
export default async function HomePage() {
const data = await fetch('https://api.example.com/data').then((r) =>
r.json(),
);
return (
<>
Home
{data.title}
>
);
}
export const getConfig = async () => {
return { render: 'static' } as const;
};
```
--------------------------------
### Configure Static App Deployment (wrangler.jsonc)
Source: https://github.com/wakujs/waku/blob/main/docs/guides/cloudflare.mdx
Configure `wrangler.jsonc` for static asset deployment to Cloudflare Workers. Specify the directory for static assets and HTML handling.
```json
{
"name": "waku-project",
"compatibility_date": "2025-11-17",
"assets": {
"directory": "./dist/public",
"html_handling": "drop-trailing-slash"
}
}
```
--------------------------------
### Slug Slice Configuration Example
Source: https://github.com/wakujs/waku/blob/main/docs/guides/custom-router.mdx
Defines a slice with a dynamic path segment, allowing it to render content based on a specific ID. Provide `pathSpec` for slug slices.
```tsx
{
type: 'slice',
id: 'product-card/[id]',
pathSpec: [
{ type: 'literal', name: 'product-card' },
{ type: 'group', name: 'id' },
],
isStatic: false,
renderer: async (params) => ,
}
```
--------------------------------
### Redirects in Netlify or Cloudflare Pages
Source: https://github.com/wakujs/waku/blob/main/docs/guides/redirect-maps.mdx
Define redirects for Netlify or Cloudflare Pages by placing a `_redirects` file in the `public` folder. This example uses a 301 permanent redirect.
```text
/old /new 301
/RSC/R/old.txt /RSC/R/new.txt 301
```
--------------------------------
### Production Build Command
Source: https://github.com/wakujs/waku/blob/main/docs/guides/static-deployments.mdx
Run the standard production build command to generate static files. The output will be placed in the `dist/public` directory.
```sh
pnpm exec waku build
```
--------------------------------
### Client-side Rendering with Waku
Source: https://github.com/wakujs/waku/blob/main/packages/website/private/contents/post-001.mdx
Use `Root` and `Slot` from `waku/client` to render server components on the client. `Root` initializes the RSC with an `initialInput`, and `Slot` displays the component associated with a specific ID.
```tsx
import { createRoot } from 'react-dom/client';
import { Root, Slot } from 'waku/client';
const rootElement = (
);
createRoot(document.getElementById('root')).render(rootElement);
```