File-Based Routing
Furin scans src/pages and turns files into routes. Pages live in .tsx files, while _route.tsx files define layouts and route-level config for a directory.
Basic Pages
text
src/pages/index.tsx -> /
src/pages/about.tsx -> /about
src/pages/blog/index.tsx -> /blog
Dynamic Segments
Use square brackets for params:
text
src/pages/blog/[slug].tsx -> /blog/:slug
src/pages/docs/[...path].tsx -> /docs/*
If you want typed params, declare them on createRoute():
src/pages/blog/[slug].tsx
import { t } from "elysia"
import { route } from "./_route"
export default route.page({
loader: async ({ params }) => {
const post = await db.getPost(params.slug)
return { post }
},
component: ({ post }) => <article>{post.title}</article>,
})
src/pages/blog/_route.tsx
import { t } from "elysia"
import { createRoute } from "@teyik0/furin/client"
import { route as rootRoute } from "../root"
export const route = createRoute({
parent: rootRoute,
params: t.Object({
slug: t.String(),
}),
})
Layout Files
Files named _route.tsx define route-level config and layouts for their directory:
text
src/pages/blog/_route.tsx
src/pages/blog/index.tsx
src/pages/blog/[slug].tsx
src/pages/blog/_route.tsx
import { createRoute } from "@teyik0/furin/client"
import { route as rootRoute } from "../root"
export const route = createRoute({
parent: rootRoute,
layout: ({ children }) => (
<div className="mx-auto flex max-w-5xl gap-8 px-4 py-10">
<aside>Sidebar</aside>
<main>{children}</main>
</div>
),
})
Catch-All Routes
Catch-all segments are written with [...name]. Furin turns them into * in the generated runtime pattern.
text
src/pages/docs/[...path].tsx -> /docs/*
If you declare a schema for that route, the runtime param key is "*":
tsx
import { t } from "elysia"
import { createRoute } from "@teyik0/furin/client"
import { route as rootRoute } from "../root"
export const route = createRoute({
parent: rootRoute,
params: t.Object({
"*": t.String(),
}),
})
Typed Navigation
Furin generates furin-env.d.ts so <Link /> can type the to pathname and per-route search object.
tsx
import { Link } from "@teyik0/furin/link"
<Link to="/docs/rendering">Rendering</Link>
When a route declares a query schema, search is typed from that schema.
tsx
<Link to="/search" search={{ page: 2 }} />
Make sure furin-env.d.ts is included in your app tsconfig.json:
json
{
"include": ["src/**/*", "furin-env.d.ts"]
}