Router Options
All configuration options for createRouter(manifest, options?). Every field is optional. The router works with zero configuration.
RouterOptions
| Option | Type | Default | Description |
|---|---|---|---|
root | string | — | Base URL for resolving module import() paths. Pass import.meta.url from your server entry. |
basePath | string | '/' | URL prefix for all routes (e.g. '/app'). |
csrfProtection | boolean | { allowedOrigins?: string[] } | true | CSRF validation on POST. Pass false to disable or an object with allowedOrigins. |
onBeforeRequest | (req) => Response | void | — | Hook called before routing. Return a Response to short-circuit. |
onNotFound | (req) => Response | 404 text | Hook called when no route matches. |
onError | (error, req) => Response | 500 text | Hook for unhandled errors. Thrown Responses never reach this hook. |
requestTimeout | number | undefined | Max request time in ms. Exceeding returns 504. Set to 0 to disable. |
mode | 'development' | 'production' | 'production' | Controls error verbosity, module caching, and HMR injection. |
hmrUrl | string | '/@vite/client' | Vite HMR WebSocket URL. Only used in development mode. |
assetPrefix | string | '/' | Public URL prefix for client chunk paths. |
clientEntry | string | — | Path to the client entry module that calls hydrateRoot(). |
streaming | boolean | 'shell' | false | HTML streaming mode. false = wait, 'shell' = recommended, true = full stream. |
nonce | string | — | CSP nonce for inline scripts. Passed to React's renderToReadableStream. |
rsc | boolean | false | Enable RSC payload negotiation for client-side SPA navigation. |
cache | CacheAdapter | — | Cross-request cache adapter for CDN or KV-level deduplication. |
CacheAdapter Interface
interface CacheAdapter {
get(key: string): unknown | Promise<unknown>;
set(key: string, value: unknown, ttl?: number): void | Promise<void>;
}Platform-specific implementations: Cloudflare caches.default, Redis, KV stores, or an in-memory LRU.
NavigationOptions
Options for initNavigation(setPage, options?) from @cmj/juice/client.
| Option | Type | Default | Description |
|---|---|---|---|
viewTransitions | boolean | true | Use the View Transitions API for page transitions. |
Full Example
import { createRouter } from '@cmj/juice/runtime';
import manifest from './flight-manifest.json';
export default {
fetch: createRouter(manifest, {
root: import.meta.url,
basePath: '/',
streaming: 'shell',
nonce: crypto.randomUUID(),
rsc: true,
csrfProtection: {
allowedOrigins: ['https://admin.example.com'],
},
requestTimeout: 30_000,
cache: {
get: (key) => globalCache.get(key),
set: (key, value, ttl) => globalCache.set(key, value, { ttl }),
},
onBeforeRequest: (req) => {
if (isMaintenanceMode()) {
return new Response('Maintenance', { status: 503 });
}
},
onNotFound: (req) => {
return new Response('Page not found', { status: 404 });
},
onError: (error, req) => {
console.error('[app]', req.url, error);
return new Response('Internal error', { status: 500 });
},
}),
};Previous
File Conventions