HonoX Architecture Guidelines
Use this skill as a project-proven, reusable baseline for HonoX applications. It is derived from a working production setup and intentionally generalized for reuse.
Version & Stack (Recommended Baseline)
- •Hono: 4.x
- •HonoX: 0.1.x
- •Runtime: Cloudflare Workers (Wrangler)
- •Build: Vite
- •CSS: Tailwind CSS v4 (or project equivalent)
- •Storage: Optional object storage (R2-compatible pattern)
Project Structure (Reusable Shape)
app/ ├─ client.ts ├─ server.ts ├─ global.d.ts ├─ style.css ├─ components/ ├─ features/ │ └─ [domain-feature].tsx ├─ islands/ │ └─ [interactive-component].tsx ├─ lib/ │ ├─ [domain-parser].ts │ └─ [storage-adapter].ts ├─ routes/ │ ├─ _renderer.tsx │ ├─ _404.tsx │ ├─ _error.tsx │ ├─ index.tsx │ ├─ [resource]/ │ │ ├─ index.tsx │ │ └─ [param].tsx │ └─ api/ │ └─ [resource]/ │ └─ [param].ts └─ utils/ └─ types.ts
File-Based Routing (Pattern)
- •
app/routes/index.tsx→/ - •
app/routes/[resource]/index.tsx→/[resource] - •
app/routes/[resource]/[param].tsx→/[resource]/:param - •
app/routes/api/[resource]/[param].ts→/api/[resource]/:param - •
app/routes/_renderer.tsx→ Global renderer/layout - •
app/routes/_404.tsx→ Not found handler - •
app/routes/_error.tsx→ Error handler
Use semantic dynamic params ([slug], [path], [id]) consistently per domain.
Entry Points
app/server.ts
import { showRoutes } from "hono/dev";
import { createApp } from "honox/server";
const app = createApp();
showRoutes(app);
export default app;
app/client.ts
import { createClient } from "honox/client";
createClient();
Prefer createClient() for HonoX 0.1.x-style client bootstrap.
Rendering & Layout Rules
Keep _renderer.tsx as the single source of shared HTML shell concerns:
- •
<Link href='/app/style.css' rel='stylesheet' /> - •
<Script src='/app/client.ts' async /> - •Shared layout (
Header,Footer, main container) - •Common OGP/Twitter defaults
- •Optional analytics initialization via env binding
Define route-level <title> and <meta> inside page routes and let head aggregation handle output.
Islands Rules
- •Put interactive components in
app/islands/ - •Import islands from server-rendered routes/components
- •Hydrate only where interaction is required
import InteractiveFilter from "../../islands/interactive-filter";
Do
- •Keep islands small and focused
- •Keep state local unless cross-island sharing is truly needed
Don't
- •Do not island-ize static markup
- •Do not move server-only logic into islands
Data Access Pattern (Storage + Cache API)
Use one dedicated adapter module (e.g. app/lib/storage.ts) for all storage reads/writes:
- •
getItem(storage, key, options) - •
listItems(storage, options) - •
getAsset(storage, path, options)
Recommended behavior:
- •Use Cache API for edge caching (
caches.open(...)) - •Use
ExecutionContext+ctx.waitUntilfor non-blocking cache writes - •Use explicit
Result<T, E>-style returns for recoverable failures - •Resolve success/error branches at route level
API Route Pattern
For asset/data proxy routes:
- •Normalize/validate route params
- •Fetch through adapter (
getAsset/getItem) - •Add observability headers like
X-Cache: HIT|MISS - •Set
Content-Type/ETag/Cache-Controlwhen available - •Return
c.notFound()for missing objects
Error Handling
- •
_404.tsx:NotFoundHandler - •
_error.tsx:ErrorHandler- •If error already exposes a response, return it directly
- •Otherwise return 500 with safe fallback UI
Env & Types
Define runtime bindings in app/global.d.ts:
Bindings: {
STORAGE_BUCKET: R2Bucket
ANALYTICS_ID?: string
}
Always update type declarations when adding/changing worker bindings.
Development Commands
pnpm run dev pnpm run test pnpm run typecheck pnpm run lint pnpm run format pnpm run build pnpm run deploy
Reusable Implementation Checklist
- •Keep route naming and dynamic segment conventions consistent
- •Add interactivity via
app/islandsfirst, not mixed server files - •Centralize storage/data access behind one adapter module
- •Preserve framework-level not-found/error flow
- •Keep shared head/layout logic in
_renderer.tsx - •Keep route-level SEO metadata close to each route
- •Add/maintain tests for parsing/storage utilities when behavior changes