Routing
Dinou uses a file-system based router. Your file structure defines your URL paths.
Overview
Any file named page.jsx, page.tsx, page.js, or page.ts inside the src directory automatically becomes a public route.
Show Technical Details (for Ejected Code)
In the ejected core, the URL path to file system mapping is fully resolved by the module dinou/core/get-file-path-and-dynamic-params.js.
This module traverses the src/ directory structure at request time, parsing folder structures to match bracket parameters ([param]), optional parameters ([[param]]), catch-all directories ([...param]), route groups ((group)), and layout slots (@slot). It returns the resolved file path along with the parsed parameters dictionary.
Basic & Dynamic Routes
Dinou supports various pattern matching strategies for dynamic routing:
| Pattern | File Path | URL Example | Params (params) |
|---|---|---|---|
| Static | src/page.jsx | / | {} |
| Dynamic | src/blog/[slug]/page.jsx | /blog/hello | { slug: 'hello' } |
| Optional | src/blog/[[slug]]/page.jsx | /blog | { slug: undefined } |
| Catch-all | src/blog/[...slug]/page.jsx | /blog/a/b/c | { slug: ['a','b','c'] } |
| Optional Catch-all | src/blog/[[...slug]]/page.jsx | /blog | { slug: [] } |
Note
params prop to page, layout, error,not_found, and slot pages. Query parameters (e.g., ?q=hello) are NOT passed as props. Use the useSearchParams() hook in Client Components, or getContext().req.query in Server Components.Optional Segments Rules
Dinou enforces a strict No-Gap Rule when using deep nested optional segments like /inventory/[[warehouse]]/[[aisle]].
You can omit optional segments only if they are at the end of the URL.
/inventory/main ✅
/inventory ✅
You cannot skip an earlier segment and define a later one.
❌ Impossible to represent in URL
Catch-all Constraints
Because Catch-all segments ([...slug]) consume the rest of the URL, they must always be the terminal (last) segment of a route definition. You cannot place other static or dynamic folders inside a Catch-all folder.
Advanced Routing
Route Groups (folder)
Folders wrapped in parentheses are omitted from the URL path.
- src/(auth)/login/page.jsx → /login
- src/(marketing)/about/page.jsx → /about
- src/(marketing)/(nested)/about/page.jsx → /about
Why use them?
Route Groups allow you to keep your project structure logical (e.g., grouping all authentication-related routes together) without affecting the public URL structure.
Parallel Routes @slot
You can define slots (e.g., @sidebar, @header) to render multiple pages in the same layout simultaneously.
- src/dashboard/@sidebar/page.jsx
- src/dashboard/(group-a)/@bottom/page.jsx
- src/dashboard/layout.jsx
The layout.jsx receives the slots as props alongside children:
function Layout({ children, sidebar, bottom })Requirement
Why use them?
Parallel routes allow independent UI sections and, crucially, Error Containment. If one section fails, it doesn't have to break the entire page.
Error Containment Behavior
Show Technical Details (for Ejected Code)
Parallel routes and slot resolutions are handled within dinou/core/get-jsx.js:
- Layout Slot Injection: The layouts resolved by
getFilePathAndDynamicParamsreturn their associated slots as properties. These are mapped and injected as props into the parentLayoutcomponent (e.g.Layout({ sidebar, bottom, children })). - Error Containment Mechanism: During layout resolution, the generator attempts to render each slot component individually using
asyncRenderJSXToClientJSXinside atry/catchblock. If a slot component fails, it catches the error, searches for a localerror.tsxwithin the slot's folder, and substitutes the slot's content with that error UI, leaving the rest of the page un-crashed.