Getting Started
  • Introduction
  • Installation
  • About
Core Concepts
  • Routing System
  • Page Functions
  • Data Fetching
  • Server Components
  • Client Components
Features
  • Dynamic & Query Parameters
  • Navigation
  • Styles & CSS
  • Images
  • Favicons
Configuration
  • Environment Variables
  • Import Aliases
  • Ejecting
dinou logodinou
docs
npmGitHub

Routing System

Learn about dinou's file-based routing system and how to create different types of routes.

Overview

dinou uses a file-based routing system where routes are defined by creating page.tsx files in folders. The routing system supports:

  • Static routes
  • Dynamic routes with parameters
  • Optional dynamic routes
  • Catch-all routes
  • Nested layouts
  • Custom not found pages
  • Custom error pages
  • Parallel routes (slots)
  • Route groups

Base Directory

All routing in dinou is defined relative to the src/ directory. The structure and naming of files inside src/ determine how routes are resolved and rendered.

Here's a summary of the special files used in routing:

  • page.tsx: Defines a route. The file path corresponds to the route path.
  • layout.tsx: Wraps a page or nested pages/layouts. Used for persistent UI such as headers, footers, sidebars, etc, or for defining the html document.
  • not_found.tsx: Defines a custom "not found" page for unmatched routes.
  • error.tsx: Defines an error page for the route. It receives params, query, and error props.
  • Slots: Folders starting with @, such as @sidebar, define parallel content and must contain a page.tsx file.
src/
├── page.tsx              # Route: /
├── layout.tsx            # Layout for /
├── not_found.tsx         # 404 page for /
├── error.tsx             # Error page for /
├── about/
│   └── page.tsx          # Route: /about
└── @sidebar/
    └── page.tsx          # Slot for sidebar content

This convention keeps your routing declarative and consistent while supporting advanced use cases like nested layouts and error boundaries.

Static Routes

Static routes are the simplest type of route, defined by folder structure:

File Structure
src/
├── page.tsx          # → /
├── about/
│   └── page.tsx      # → /about
└── blog/
    ├── page.tsx      # → /blog
    └── post/
        └── page.tsx  # → /blog/post

Each page.tsx file exports a React component (client or server component):

// src/about/page.tsx
"use client";

export default function Page() {
  return <h1>About Us</h1>;
}

Dynamic Routes

Dynamic routes are created using square brackets in folder names. The parameter value is passed to your component as props:

Dynamic Route Example
src/blog/[id]/page.tsx  # → /blog/:id
// src/blog/[id]/page.tsx
"use client";

export default function Page({ 
  params 
}: { 
  params: { id: string } 
}) {
  return <h1>Blog Post: {params.id}</h1>;
}

Accessing /blog/123 will pass { params: { id: "123" } } to the component.

Optional Dynamic Routes

Optional dynamic routes use double square brackets [[param]] and match both with and without the parameter:

src/blog/[[category]]/page.tsx

This matches both:

  • /blog → { params: { category: undefined } }
  • /blog/tech → { params: { category: "tech" } }
// src/blog/[[category]]/page.tsx
"use client";

export default function Page({ 
  params 
}: { 
  params: { category?: string } 
}) {
  return (
    <h1>
      {params.category ? `Category: ${params.category}` : 'All Posts'}
    </h1>
  );
}

Catch-All Routes

Catch-all routes capture multiple path segments as an array:

Catch-All Routes [...param]

src/wiki/[...slug]/page.tsx  # → /wiki/*

Examples:

  • /wiki/a → { params: { slug: ["a"] } }
  • /wiki/a/b/c → { params: { slug: ["a", "b", "c"] } }

Optional Catch-All Routes [[...param]]

src/wiki/[[...slug]]/page.tsx  # → /wiki or /wiki/*

Examples:

  • /wiki → { params: { slug: [] } }
  • /wiki/a/b → { params: { slug: ["a", "b"] } }
// src/wiki/[[...slug]]/page.tsx
"use client";

export default function Page({ 
  params 
}: { 
  params: { slug: string[] } 
}) {
  return (
    <div>
      <h1>Wiki</h1>
      <p>Path: /{params.slug.join('/')}</p>
    </div>
  );
}

Layouts

Layouts wrap page content and can be nested. Create a layout.tsx file in any folder to define a layout:

// src/blog/layout.tsx
"use client";

import type { ReactNode } from "react";

export default function Layout({ 
  children 
}: { 
  children: ReactNode 
}) {
  return (
    <div>
      <nav>Blog Navigation</nav>
      <main>{children}</main>
    </div>
  );
}
Layouts automatically wrap all pages in their folder and subfolders. You can skip layouts by adding a no_layout file (without extension) in the same folder as your page.
You can add a reset_layout file (without extension) in the same folder as your nested layout to make it the first applied. This is useful for example when you have a landing page in /.

Parallel Routes (Slots)

Parallel routes, also known as slots, are defined using directory names that start with @, such as @sidebar. These slots are passed into layouts as props, allowing you to render multiple parts of a page in parallel.

// File structure:
src/@sidebar/page.tsx
src/page.tsx
src/layout.tsx

The content from @sidebar/page.tsx is passed into layout.tsx as props.sidebar. You can render the slot in your layout like this:

"use client";

import type { ReactNode } from "react";

export default function Layout({
  children,
  sidebar,
}: {
  children: ReactNode;
  sidebar: ReactNode;
}) {
  return (
    <html lang="en">
      <head>
        <title>dinou app</title>
      </head>
      <body>
        {sidebar}
        {children}
      </body>
    </html>
  );
}

Slots are especially useful when rendering persistent UI components like sidebars, headers, or other parallel content areas that accompany the main page content.

Slots receive query and dynamic parameters as the rest of pages (layouts, pages, not found pages, and error pages).

Not Found Pages

Create custom 404 pages by adding not_found.tsx files:

// src/not_found.tsx
"use client";

export default function Page() {
  return (
    <div>
      <h1>404 - Page Not Found</h1>
      <p>The page you're looking for doesn't exist.</p>
    </div>
  );
}

If multiple not_found.tsx files exist in a route hierarchy, the most nested one will be used.

Layouts are applied to not found pages too, unless a no_layout or no_layout_not_found file (without extension) is found in the same folder as your not found page.

Error Handling

Create custom error pages by adding error.tsx files:

// src/error.tsx
"use client";

export default function Page({
  error: { message, stack },
}: {
  error: Error;
}) {
  return (
    <main className="flex-1 flex flex-col items-center justify-center p-4">
      <div className="max-w-md w-full text-center space-y-6">
        <h1 className="text-3xl font-bold text-red-600">Error</h1>
        <p className="text-lg text-gray-700">
          An unexpected error has occurred. Please try again later.
        </p>
        <a
          href="/"
          className="inline-block px-6 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"
        >
          Go to Home
        </a>
      </div>
      <div className="mt-6 text-sm text-gray-500">
        <pre className="whitespace-pre-wrap break-words">{message}</pre>
        <pre className="whitespace-pre-wrap break-words">{stack}</pre>
      </div>
    </main>
  );
}

The most nested error.tsx file in a route hierarchy will be used. In production, if no error page is present, the error will be written to the console. In development, a default debug error page is shown.

Layouts are applied to error pages unless a no_layout or no_layout_error file (without extension) is present in the same folder as the error.tsx page.
Avoid using async functions (server components) and fetching data directly in error.tsx pages. These are rendered dynamically and delaying rendering is discouraged. Use Suspense if needed.

The error page receives three props: params, query, and error. The error object contains a message and a stack, both strings.

Route Groups

Route groups are defined using directory names wrapped in parentheses, such as (group). They allow you to organize routes in your filesystem without affecting the URL structure.

// src/(auth)/login/page.tsx → "/login"
// src/(auth)/signup/page.tsx → "/signup"

The directory name (auth) is ignored in the final URL, so both pages above will be rendered at the root level:/login and /signup.

This is useful for grouping related pages (like authentication-related routes) together in the codebase without adding a prefix to the URL path.

You can nest route groups.

On This Page

OverviewBase DirectoryStatic RoutesDynamic RoutesOptional Dynamic RoutesCatch-All RoutesLayoutsParallel Routes (Slots)Not Found PagesError HandlingRoute Groups