Dynamic Routes
Wrap a folder name in brackets to capture a path segment.
| Folder | Matches | router.params |
|---|---|---|
app/blog/[slug]/page.jsx | /blog/hello | { slug: "hello" } |
app/docs/[...path]/page.jsx | /docs/a/b/c | { path: ["a", "b", "c"] } |
[param] matches one segment; [...rest] is a catch-all matching the remainder.
Reading params
Params are exposed on the reactive router:
import { router } from "@opentf/afw"; export default function Post() { return <h1>Post: {router.params.slug}</h1>; }
Reading router.params inside a binding keeps the view in sync as you navigate between matching routes.
Generating static paths
Export getStaticPaths() from a dynamic page to list its URLs for prerendering:
export function getStaticPaths() { return [{ params: { slug: "hello" } }, { params: { slug: "hello world" } }]; }
Pass raw parameter values: the framework encodes URL segments and decodes them when matching a route. For catch-all routes, pass an array such as { params: { path: ["guides", "getting started"] } }.
Missing parameters, empty segments, invalid values and duplicate URLs fail the build with an error. getStaticPaths() must return an array. It describes URLs; props entries are unsupported. Use a route loader and router.data to supply page data during prerendering, SSR and navigation.
Per-path metadata
Export generateMetadata({ params }) on a dynamic page when each path needs its own <title>, description, or share image. With a configured prerender target, pair it with getStaticPaths so every enumerated path is pre-rendered with the correct head. A dynamic route without getStaticPaths is skipped at build time but still resolves generateMetadata on each request through an app-provided request renderer / SSR. See Metadata & SEO.