Quick start
This guide creates a working Hono + Vue 3 project from scratch. Adapt the imports for React or another router as needed.
Shortcut —
inertia init my-appgenerates all of this automatically. See CLI.
Minimal structure
my-app/
├── deno.json
├── package.json
├── vite.config.ts
├── server.ts
└── src/
├── main.ts
└── pages/
└── Home.vue1. server.ts
ts
import { Hono } from "hono"
import { createInertia, pageToDiv, readViteManifest } from "deno-inertia"
import { toWebRequest } from "deno-inertia/hono"
const IS_PROD = Deno.env.get("PROD_MODE") === "1"
const PORT = Number(Deno.env.get("PORT") ?? 3000)
const VITE_URL = Deno.env.get("VITE_URL") ?? "http://localhost:5173"
// Production: read the manifest generated by vite build
const manifest = IS_PROD
? await readViteManifest("dist/.vite/manifest.json")
: null
const inertia = createInertia({
version: "1.0.0",
// Assets: Vite in dev, manifest in prod
...(IS_PROD && manifest
? { prod: { manifest, entry: "src/main.ts" } }
: { vite: { url: VITE_URL, entry: "/src/main.ts" } }),
// Full HTML template
template: (page, assets) => `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My App</title>
${assets}
</head>
<body>
${pageToDiv(page)}
</body>
</html>`,
})
const app = new Hono()
// Main route — renders the "Home" component with props
app.get("/", async (c) =>
inertia.render(toWebRequest(c), "Home", {
message: "Hello from Hono + Vue",
}),
)
Deno.serve({ port: PORT }, app.fetch)
console.log(`Server running at http://localhost:${PORT}`)2. src/main.ts (Vue)
ts
import { createApp, h } from "vue"
import { createInertiaApp } from "@inertiajs/vue3"
createInertiaApp({
resolve: (name) => {
const pages = import.meta.glob("./pages/**/*.vue", { eager: true })
const page = pages[`./pages/${name}.vue`]
if (!page) throw new Error(`Page not found: "${name}"`)
return page as object
},
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})3. src/pages/Home.vue
vue
<script setup lang="ts">
defineProps<{ message: string }>()
</script>
<template>
<h1>{{ message }}</h1>
</template>4. deno.json
jsonc
{
"imports": {
"deno-inertia": "jsr:@streemkit/inertia-deno",
"deno-inertia/hono": "jsr:@streemkit/inertia-deno/hono",
"hono": "jsr:@hono/hono@^4"
},
"tasks": {
"install": "npm install",
"dev": "deno run -A jsr:@streemkit/inertia-deno-cli dev",
"build": "deno run -A jsr:@streemkit/inertia-deno-cli build",
"preview": "deno run -A jsr:@streemkit/inertia-deno-cli preview"
},
"compilerOptions": {
"lib": ["deno.ns", "dom", "dom.iterable", "esnext"]
}
}5. Run the project
bash
npm install # install Vite + Vue
deno task dev # start Vite (:5173) + Deno (:3000)Open http://localhost:3000 — you'll see the message from your server.
What happens
- The browser loads
http://localhost:3000/ - Deno responds with full HTML (first visit) containing
<div id="app" data-page="…"> - Vite injects
@vite/client(HMR) andsrc/main.ts - Vue mounts the
Homecomponent and hydrates the JSON props - Subsequent navigations (
<Link href="…">) sendX-Inertia: true→ Deno responds with JSON → Vue updates the page without a full reload
Next steps
- Configuration — advanced
createInertia()options - Props — lazy, deferred, merge props
- Forms — validation + error bags
- CLI — generate a full project with
inertia init