yusukebe/skills · Archived

hono-inertia

Use @hono/inertia on the server and @ts-76/inertia-hono-jsx on the client to get SPA-style interactivity without leaving the Hono/hono-jsx stack.

Trending #7798 First seen May 21, 2026

Installation

$ npx skills add yusukebe/skills --skill hono-inertia

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from yusukebe/skills.

npx skills add yusukebe/skills

Browse all from yusukebe/skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 36
Default branch main
Status Archived

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 5,661 B
  • docs SUMMARY.md 165 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 40 installs

SKILL.md

Build SPA-feel apps with Inertia.js + Hono + hono/jsx

Inertia.js lets you build single-page apps without writing a separate frontend or a JSON API layer. The server returns Inertia responses (page name + props), and a thin client adapter swaps the current page component on the fly. With Hono as the server and hono/jsx as the client, you get SPA interactivity while staying inside one TypeScript stack — no React.

Reach for this when server-rendered hono/jsx is no longer enough — that is, when you need client-side state, optimistic UI, or rich forms.

Stack

  • Server: hono + @hono/inertia. The inertia({ rootView }) middleware adds c.render(name, props) for returning Inertia responses.
  • Client: @ts-76/inertia-hono-jsx. Provides createInertiaApp, <Link>, <Form>, <Head>, useForm, useHttp, etc., on top of @inertiajs/core and hono/jsx/dom.
  • Bundling / SSR: Vite (with @cloudflare/vite-plugin when deploying to Workers) and vite-ssr-components for asset wiring. Start from the cloudflare-workers+vite Hono starter template — it has the Vite + Workers wiring already in place: <https://github.com/honojs/starter/tree/main/templates/cloudflare-workers+vite>;.
  • Page typing: @hono/inertia/vite generates pages.gen.ts so PagePropsFor<Name> resolves to the props passed to c.render(Name, ...).

Reference example

yusukebe/hono-inertia-example is the canonical layout (Hono + Inertia on Cloudflare Workers). It is written in React, so do not copy its app/client.tsx and app/root-view.tsx verbatim — those need to be rewritten against @ts-76/inertia-hono-jsx and hono/jsx. The server side (app/server.ts, route shape, Vite config, wrangler.jsonc, validation with @hono/zod-validator) transfers as-is.

<https://github.com/yusukebe/hono-inertia-example>;

Server sketch

// app/server.ts
import { Hono } from 'hono'
import { inertia } from '@hono/inertia'
import { rootView } from './root-view'

const app = new Hono()

app.use(inertia({ rootView }))

const routes = app
  .get('/', (c) => c.render('Home', { message: 'Hono x Inertia' }))
  .get('/users', (c) => c.render('Users/Index', { users: listUsers() }))
  .get('/users/:id{[0-9]+}', (c) => {
    const id = Number(c.req.param('id'))
    const user = findUser(id)
    if (!user) return c.notFound()
    return c.render('Users/Show', { user })
  })

export default routes

c.render(name, props) returns either a full HTML document (on the first request) or a JSON Inertia page object (on subsequent client navigations) — @hono/inertia looks at the X-Inertia request header to decide.

Client sketch (hono/jsx)

// app/client.tsx
import { createInertiaApp } from '@ts-76/inertia-hono-jsx'

createInertiaApp({
  resolve: (name) => {
    const pages = import.meta.glob('./pages/**/*.tsx', { eager: true })
    return pages[`./pages/${name}.tsx`]
  },
})

Without a custom setup, the adapter mounts <App /> for you. It uses hydrateRoot (from hono/jsx/dom) when the root has data-server-rendered, and createRoot otherwise.

Page component (hono/jsx)

// app/pages/Users/Index.tsx
import { Head, Link, type PageComponent } from '@ts-76/inertia-hono-jsx'

const UsersIndex: PageComponent<'Users/Index'> = ({ users }) => (
  <main>
    <Head title='Users' />
    <h1>Users</h1>
    {users.map((u) => (
      <Link href={`/users/${u.id}`} key={u.id}>
        {u.name}
      </Link>
    ))}
  </main>
)

export default UsersIndex

PageComponent<'Users/Index'> pulls the prop type from pages.gen.ts, which is generated by @hono/inertia/vite from the server routes — so a mismatch between server and client props is a build error, not a runtime one.

Defaults

  • Set jsxImportSource: "hono/jsx" in tsconfig.json.
  • Use vite-ssr-components/hono (not /react) in root-view.tsx to inject the Vite client and asset tags.
  • Deploy with @cloudflare/vite-plugin so wrangler deploy ships the SSR worker and the client bundle together.

Pitfalls

  • @ts-76/inertia-hono-jsx is community-scoped and "partial" hono/jsx support per its README — browser rendering targets hono/jsx/dom, but server-side rendering fidelity is not React-grade. Verify SSR output for any non-trivial page.
  • Inertia is not an API framework. If a non-Inertia client (mobile, third-party) needs the same data, build a separate JSON endpoint — do not try to reuse the Inertia response shape.
  • Asset versioning: make sure X-Inertia-Version matches your client bundle hash, or clients silently force a full reload on every navigation.
  • On Cloudflare Workers, serve the client bundle via Workers Assets (@cloudflare/vite-plugin handles this), not via fetch-to-R2.

Going deeper