Routes
A file in src/routes/ defines a URL, its page, and any request handlers it needs.
Pages and handlers
A default export is the React page. Without an explicit GET handler, Goribu renders it directly:
export const meta = { title: "About" };
// This page has no request-time data to load.
export default function AboutPage() {
return <main><h1>About our app</h1></main>;
}Export a named HTTP handler when the response needs request data. Return res.render(props) to render the page in that same file. A route with only handlers is an API endpoint; it does not need a React component.
File-based URLs
| File | URL |
|---|---|
src/routes/index.jsx | / |
src/routes/about.jsx | /about |
src/routes/posts/index.jsx | /posts |
src/routes/posts/new.jsx | /posts/new |
src/routes/posts/[id].jsx | /posts/42 |
Use .js, .jsx, .ts, or .tsx. A terminal index maps to its containing folder. TypeScript declaration files are ignored, and symlinks are not followed.
Static segments win over dynamic segments: /posts/new matches posts/new.jsx before posts/[id].jsx.
Dynamic parameters
Square brackets capture one URL segment. Read the value as a string from req.params:
// Read the dynamic segment before rendering the page.
export function GET(req, res) {
return res.render({ name: req.params.name });
}
// React escapes the supplied name when rendering text.
export default function HelloPage({ name }) {
return <h1>Hello, {name}.</h1>;
}Parameter names may contain letters, digits, and underscores, and must be distinct within one route. Catch-all and optional segments are not supported.
Pre-rendered pages
A page is a static candidate when its URL is known at build time, it has no HTTP handlers or selected middleware, and it has not opted out. Goribu renders it during the build and serves its HTML from Cloudflare Static Assets without invoking the Worker for that document request.
Static output can still hydrate, use React state, and run client-side navigation. Static describes how the initial HTML is served, not whether the page is interactive.
Use a route export to make the choice explicit:
export const prerender = false;false keeps the page on the Worker. true requires static output and fails the build if Goribu cannot produce it. An explicit true can opt a GET handler into build-time rendering, but cannot be combined with non-GET handlers, dynamic segments, or middleware.
A static candidate that cannot render at build time normally falls back to the Worker with a build message. A forced prerender = true fails instead. Request-specific pages should remain Worker-served.
A static page can submit a Form to a separate action route. Keeping mutation handlers in the page's own file also works; that URL then stays on the Worker.
Routing rules
- Every route needs a page, at least one HTTP handler, or both.
- Two files with the same URL shape fail the build.
posts/[id].jsxandposts/[slug].jsxconflict. - Names beginning with
_are not URLs. Underscore-prefixed folders exclude their subtree. - Keep
.server.*helpers outsidesrc/routes/and import them from handlers or middleware. /_goribu/is reserved for framework assets and protocols.- Do not place public HTML files at URLs already owned by routes.
_document, _404, _500, and folder-level _middleware have special roles. See Rendering, Errors, and Request handlers.
HTTP defaults
A page has an implicit GET. An explicit handler answers its own method. Goribu derives HEAD from GET when needed, answers automatic OPTIONS with 204 and an Allow header, and returns 405 for unsupported methods.
Unmatched URLs return 404. Trailing slashes redirect to the slash-free URL, except for /; static assets use the same canonical shape.