Routing

Routes come straight from the filesystem under src/.

src/
  index.ht.js              → /
  about.ht.js              → /about
  blog/
    index.ht.js            → /blog
    [slug].ht.js           → /blog/:slug
  docs/
    [...path]?.ht.js       → /docs, /docs/a, /docs/a/b, ...
  (admin)/
    users.ht.js            → /users
  404.ht.js                → dist/404.html

Route table

FeatureFileURL
Staticindex.ht.js/
Nestedblog/index.ht.js/blog
Dynamicblog/[slug].ht.js/blog/my-post
Multiple paramsblog/[year]/[slug].ht.js/blog/2026/my-post
Catch-alldocs/[...path].ht.js/docs/api/auth
Optional catch-alldocs/[...path]?.ht.js/docs + deeper
Route groups(admin)/users.ht.js/users

More specific routes win: static beats dynamic, dynamic beats catch-alls. Two files generating the same URL is a build error.

generateStaticParams

Dynamic routes declare which pages to emit at build time. In sitelo (dev), dynamic routes still render on demand without listing every param.

Values can be strings, numbers, or booleans — they are stringified and URL-encoded. Catch-all params accept arrays ({ path: ['a', 'b'] }) or slash-separated strings ({ path: 'a/b' }).

A dynamic page that generates zero routes prints a warning so it cannot silently vanish from your site.