Routing & Transitions

Dynamic Routes

Dynamic route segments, catch-all routes, optional segments, and advanced routing patterns in Manic.

Dynamic Routes

TL;DR

Dynamic routes use [param] syntax to capture URL segments at runtime. Manic supports single segments [id], nested segments [userId]/[postId], and catch-all segments [...slug].

What It Is

Dynamic routes allow your application to handle variable URL segments without creating individual files for each possible value:

PatternSyntaxMatchesCaptures
Single[id]/posts/123{ id: "123" }
Multiple[userId]/[postId]/users/1/posts/99{ userId: "1", postId: "99" }
Catch-all[...slug]/docs/a/b/c{ slug: "a/b/c" }

Prerequisites


Quick Start

Create a Dynamic Route

// app/routes/posts/[id].tsx
import React from 'react';
import {  } from 'manicjs';

export default function () {
  const {  } = ();

  return (
    <>
      <>Post #{.}</>
      <>Reading post data for ID: {.}</>
    </>
  );
}

Single Dynamic Segment

Use [param] to capture a single URL segment:

// app/routes/users/[id].tsx
import React from 'react';
import {  } from 'manicjs';

export default function () {
  const {  } = ();
  
  return <>User ID: {.}</>;
}

Matches:

  • /users/123{ id: "123" }
  • /users/hello-world{ id: "hello-world" }
  • /users/123/comments (too many segments)

Multiple Dynamic Segments

Nest folders to capture multiple params:

// app/routes/users/[userId]/posts/[postId].tsx
import React from 'react';
import {  } from 'manicjs';

export default function () {
  const {  } = ();
  
  return <>User {.}, Post {.}</>;
}

Matches:

  • /users/42/posts/99{ userId: "42", postId: "99" }

Catch-All Routes

Use [...param] to match any number of segments:

// app/routes/docs/[...slug].tsx
import React from 'react';
import {  } from 'manicjs';

export default function () {
  const {  } = ();  // slug = "guides/installation"
  
  return <>Doc: {.}</>;
}

Matches:

  • /docs/guides{ slug: "guides" }
  • /docs/guides/installation{ slug: "guides/installation" }
  • /docs/api/v2/endpoints/users{ slug: "api/v2/endpoints/users" }

Combining Catch-All with a Folder Index

To match both /docs and /docs/anything/below, pair a folder index.tsx with a sibling catch-all file:

index.tsx
[...slug].tsx

The static index.tsx wins for /docs (score 200) and [...slug].tsx handles every deeper URL (score 101).


API Routes

Dynamic routes work the same way in app/api/:

// app/api/users/[id]/index.ts
import {  } from 'hono';

const  = new ();

.('/', () => {
  const  = ..('id');
  return .({  });
});

export default ;

See Also

On this page