Documentation

Architecture

How VitNode combines TanStack Start for UI and isomorphic routing with Hono for API authorization and database access.

A VitNode app is two layers in one project. TanStack Start renders the pages, and a Hono API answers every request for data. Read this page to know which layer owns a job before you write code for it.

  1. TanStack Start: the UI, server-side rendering (SSR), routing and the client cache.
  2. Hono API: API routes, sessions, staff permissions and database access.

Who owns what

ResponsibilityTanStack Start (web app)Hono (API)
RoutingPage URLs, dynamic parameters, nested layoutsAPI routes under /api/*
Data fetchingRoute loaders and the universal fetcherQueries through Drizzle ORM
State & cacheTanStack Query client cacheRedis domain cache and the database
SecurityUI guards (redirecting signed-out visitors)Enforces authentication, permissions, CSRF and rate limits
The API is the security boundary

Route guards (beforeLoad) improve the experience by redirecting visitors early, but anyone can call the API directly. Every private endpoint checks the session cookie and permissions on every request.

Request flow

When a visitor opens a page such as /blog:

StepRuns onWhat happens
1. RequestBrowserThe visitor navigates to /blog
2. RoutingServer (SSR) / browserTanStack Router matches the route and runs its loader
3. Query warmingServer / browsercontext.queryClient.query runs the query, which calls the fetcher
4. API callServer / browserThe universal fetcher calls the Hono endpoint by plugin id
5. API middlewareServer (Hono)Reads the session cookie, applies rate limits, provides c.get("db")
6. HandlerServer (Hono)The route validates its input and queries PostgreSQL through Drizzle
7. ResponseServer / browserThe JSON fills the TanStack Query cache and the component renders

Request middleware

Before a page route matches, every request passes through the middleware that createVitNodeStart installs in src/start.ts, in this order:

  1. CSRF, for server function calls.
  2. Locale, for page requests: canonical 308 redirects, the locale cookie, and, on HTML responses, Cache-Control: private, no-store plus the security headers.
  3. Your own requestMiddleware, in the order you list it.

An app cannot put its own middleware in front of the first two. /api/* passes through untouched, so the Hono API sees the request exactly as the client sent it and keeps its own caching policy. The details, and how to add your own middleware, are in Configuration.

Plugins

Features live in plugins, each a package in plugins/* or node_modules:

  • Separate packages. A plugin compiles to its own dist/ folder. Its imports of React, Hono, Drizzle and other packages stay imports, so the app installs them once.
  • Declared, not wired by hand. The plugin declares its routes, AdminCP navigation and database tables, and the app's build generates the imports.
  • Only configured plugins ship. A plugin that is not listed in vitnode.config.ts and vitnode.api.config.ts adds no code to the build.