src/routes and registers each file on a Hono app. There is no route manifest you edit by hand.
Pages vs APIs
.tsx/.jsxfiles are React pages..md/.mdxfiles are also pages. Same layouts, middleware, and loaders — see Markdown pages..ts/.jsfiles are API routes..server.tsxfiles are never routes. They attach to the page with the same stem (users/[id].tsx+users/[id].server.tsx).
index.tsx in a folder is the folder URL: src/routes/settings/index.tsx → /settings.
Dynamic segments
src/routes/users/[id].tsx
[...slug] and become Hono’s :slug{.*}. The rest of the path is in params.slug.
Query strings are not part of the file name. Read them in a loader with c.req.query() or in the page with useQuery().
What is not a route
Route groups
(admin)/settings.tsx maps to /settings. The (admin) folder is only for organization — useful when two areas should not share a layout folder.
Environment-only routes
.dev / .prod suffix is stripped from the URL.
API handlers
API files export HTTP methods.defineHandler turns return values into responses and can take Hono middleware.
src/routes/api/users/index.ts
Pages can export the same HTTP methods from
.server.tsx if you want a JSON endpoint on the page URL (for example POST /users/:id next to the HTML page). If both action and POST exist, action wins for form posts.
Validation
defineHandler.withValidator() accepts any Standard Schema library (Zod, Valibot, ArkType):
400 with { error: "Validation failed", issues }.
CSS, images, and public/
Import CSS from a layout or page. Vite handles it in dev and the client build:
src/routes/_layout.tsx
public/ (/favicon.ico, /robots.txt). They land in dist/client.
There is no first-class CSS-in-JS runtime. Tailwind is a normal Vite setup: add Tailwind, import its CSS in _document.tsx or the root layout.
TypeScript
See TypeScript fortsconfig and how to share loader props with a page.