Skip to content

Routing conventions, validation, middleware composition and the fetch clients are identical across every framework.

This page is about the places where they aren't - gathered here so you can choose a stack without hunting through six pages of info boxes.

Backends

HonoH3Koa
RuntimesNode · Deno · Bun · Workers · edgeNode · Deno · Bun · edgeNode (Deno/Bun via node:http compat)
Handler stylereturn ctx.json() / ctx.text()return the value directlymutate ctx.body
Raw paramsctx.req.param()event.context.paramsctx.params
Validated paramsctx.validated.paramsctx.validated.paramsctx.validated.params
Route-specific typesVariables, BindingsContextState, Context
Global types (api/env.d.ts)DefaultVariables, DefaultBindingsDefaultContextDefaultState, DefaultContext
Error entry pointapp.onError()app.use(onError(...))middleware around await next()
Mixed segments⚠️ partial⚠️ partial✅ full
Power syntax⚠️ matches, params renamed _0abc❌ won't match✅ full

Choosing: take Hono for maximum performance and the widest runtime reach; H3 for the same, with a stronger Web-standards focus; Koa for a mature Node ecosystem - and it is the only backend with complete mixed-segment and power-syntax support.

Details ›

Frontends

ReactSolidJSVueSvelteMDX
Page extension.tsx.tsx.vue.svelte.mdx / .md
Layout filelayout.tsxlayout.tsxlayout.vuelayout.sveltelayout.mdx
Renders children with<Outlet/>props.children<RouterView/>{@render children()}props.children
jsxImportSourcereactsolid-jsvue (JSX only)n/apreact
Data loading exportloaderpreloadloaderloaderloader
Reading loaded datauseLoaderData (react-router)createAsyncuseLoaderData (_/use)useLoaderData (_/use)useLoaderData (_/use)
Needs <Suspense>
_/use module⚠️ useLoaderData only
Streaming SSR
SSG
TanStack Query
TanStack read hookuseQuery(opts)useQuery(() => opts)useQuery(opts)createQuery(() => opts)
Mixed segments⚠️ .ext suffix only
Power syntax

Reading the exceptions

  • SolidJS is the only frontend that needs a <Suspense> boundary in the common case. createAsync suspends; the other frameworks' loaders resolve before render. KosmoJS ships no boundary for you - scoping it is your call. Why ›
  • Svelte and MDX render to strings only. They implement renderToString but not renderToStream, and their folders don't accept the streaming renderMode.
  • SSG is MDX-only. For other frameworks, use SSR - or put an MDX folder next to your app folder, which is the intended shape.
  • MDX has no client runtime, so TanStack Query is unavailable there. Fetch with an MDX loader instead.
  • Svelte does not use SvelteKit. KosmoJS uses only Svelte's UI layer, so data loading is the loader export, not SvelteKit's load, and there are no +page files.

Routing Syntax Support

The parameter syntaxes are the same everywhere; only the exotic ones vary.

SyntaxExampleEverywhere?
Required [id]users/[id]✅ all backends and frontends
Optional {id}users/{id}✅ all backends and frontends
Splat {...path}docs/{...path}✅ all backends and frontends
Mixed segmentfiles/[name].[ext]⚠️ see tables above
Power syntaxbook{-:id}-info⚠️ Koa only

Practical rule: keep frontend routes to the three plain syntaxes. Use mixed segments on the API side, where support is complete on Koa and workable on Hono/H3. Reach for power syntax only on a Koa backend.

Parameter details ›

Mixing Frameworks

Support differences are per source folder, not per project - a folder runs exactly one frontend and at most one backend. So the differences above are choices you make per app, not constraints you carry project-wide:

txt
src/
├── marketing/    MDX + SSG        → static, no backend
├── app/          React + Hono     → SSR, streaming, TanStack Query
└── admin/        Vue + H3         → CSR

A folder also ignores other frameworks' files: a Vue folder skips .tsx, a React folder skips .vue/.svelte. Details ›

Released under the MIT License.