Every .ts file in pages/ automatically becomes a route. No configuration needed.
| File | Route |
|---|---|
pages/index.ts | / |
pages/about.ts | /about |
pages/blog/index.ts | /blog |
pages/blog/[slug].ts | /blog/:slug |
pages/docs/[...path].ts | /docs/* (catch-all) |
Wrap a filename segment in brackets for dynamic parameters:
// pages/blog/[slug].ts export class PageBlogSlug extends LitElement { // The slug attribute is set automatically by the router static properties = { slug: {} }; slug = ''; render() { return html`<h1>Post: ${this.slug}</h1>`; } }
Use [...name] to match any number of path segments:
// pages/docs/[...path].ts // Matches /docs/intro, /docs/guide/routing, /docs/a/b/c export class PageDocsPath extends LitElement { static properties = { path: {} }; path = ''; // "intro", "guide/routing", etc. }
Folders starting with _ are ignored by the router. Use them to colocate components, utilities, or shared code alongside your pages without creating routes:
pages/ ├── feed/ │ ├── index.ts → /feed │ └── _components/ → ignored (not a route) │ ├── post-card.ts │ └── feed-filter.ts ├── _shared/ → ignored (not a route) │ └── format-date.ts ├── _layout.ts → layout (special _ file) └── _middleware.ts → middleware (special _ file)
Files starting with _ are also skipped, except for the special _layout.ts and _middleware.ts files which have their own meaning.
Routes are matched in priority order: static routes first, then dynamic, then catch-all. This means /about always matches about.ts over [slug].ts.
LumenJS includes a client-side router. Internal links navigate without a full page reload. Use standard <a href="..."> tags. The router intercepts them automatically.