Skip to content
brought to you byVoidZero

Project Structure ​

Overview ​

A Void app uses file-based conventions to define routes, pages, middleware, and more. All directories are optional, so you only need the pieces your app actually uses.

  • routes/API endpoints (file-based routing)
  • pages/Full-stack server-rendered pages
  • middleware/Global request middleware
  • db/Drizzle schema and SQL migrations
  • crons/Scheduled cron jobs
  • queues/Async queue consumers
  • src/Shared app code
  • public/Static assets (served as-is)
  • .void/Auto-generated (gitignored)
  • vite.config.tsVite config with voidPlugin()
  • void.jsonVoid project config (optional)
  • .envEnvironment variables
  • package.json
  • tsconfig.json

routes/ ​

File-based HTTP API endpoints built on Hono. Each file exports named HTTP method handlers.

  • routes/
    • api/
      • hello.ts→ GET|POST /api/hello
      • users/
        • index.ts→ GET|POST /api/users
        • [id].ts→ GET|PUT|DELETE /api/users/:id
      • search/
        • [...query].ts→ GET /api/search/* (catch-all)
  • Named exports: export const GET = defineHandler(...), export const POST = ...
  • Dynamic segments: [id] becomes :id route parameter
  • Catch-all: [...slug] matches the remaining path
  • Route groups: (admin)/ organizes files without affecting URL paths
  • Files starting with _ are ignored
  • Environment suffix: debug.dev.ts builds in development only, metrics.prod.ts in production only

See Server Routing for the full guide.

pages/ ​

Full-stack server-rendered pages with co-located data loading. Available with Vue, React, Svelte, and Solid adapters.

  • pages/
    • layout.tsxRoot layout (wraps all pages)
    • index.tsx→ /
    • index.server.tsServer-side loader & action for /
    • about.tsx→ /about
    • users/
      • layout.tsxNested layout for /users/*
      • [id].tsx→ /users/:id
      • [id].server.tsServer-side loader & action for /users/:id
    • blog/
      • hello.md→ /blog/hello (Markdown page)
  • .server.ts files export loader for GET data and action for mutations, paired with the page component of the same name
  • Layouts nest automatically and persist across navigations
  • Markdown pages are supported with frontmatter

See Pages Routing for the full guide.

middleware/ ​

Global middleware that runs on every request. Numeric prefixes control execution order.

  • middleware/
    • 01.logger.tsRuns first
    • 02.auth.tsRuns second

Each file exports a defineMiddleware() handler. Use middleware to set shared context (auth, logging, rate limiting) available to all routes.

db/ ​

Drizzle schema and SQL migration files for the D1 database.

  • db/
    • schema.tsDrizzle schema (source of truth)
    • schema/Optional: split into multiple files
    • migrations/
      • 20260410161500_*.sql
      • 20260410161501_*.sql
  • db/schema.ts: your Drizzle table definitions and the source of truth for DB types
  • db/schema/: optional. Split tables into separate files and re-export them from db/schema.ts
  • db/migrations/: generated SQL migration files, applied in order on deploy

Generate schema with void gen model or write it by hand. Generate migrations with void db generate.

crons/ ​

Scheduled jobs that run on a cron schedule.

ts
// crons/heartbeat.ts
import { defineScheduled } from 'void';

export const cron = '*/5 * * * *';

export default defineScheduled(async (controller, env) => {
  // runs every 5 minutes
});

queues/ ​

Async queue consumers for background job processing.

ts
// queues/email.ts
import { defineQueue } from 'void';

export default defineQueue(async (batch, env) => {
  for (const msg of batch.messages) {
    // process message
  }
});

src/ ​

Shared application code such as components, utilities, and types. This directory has no special convention, so organize it however you like.

public/ ​

Static assets served as-is at the root path. Files here are not processed by Vite.

.void/ ​

Auto-generated directory (gitignored). Contains:

Generate or refresh it with void prepare, or let vite dev / vite build populate it during normal app workflows.

  • .void/
    • db.d.tsDrizzle DB instance types
    • routes.d.tsTyped fetch client types
    • queues.d.tsQueue consumer types
    • tsconfig.jsonTypeScript config fragment
    • v3/Local dev state (D1, KV, R2)

Config Files ​

FilePurpose
vite.config.tsVite configuration. Must include voidPlugin().
void.jsonOptional Void config for routing, inference, and worker settings
tsconfig.jsonTypeScript config. Extend .void/tsconfig.json for auto-generated types; run void init --tsconfig when an existing config already uses extends.
.envLocal development values only (gitignored; never deployed)
env.tsChecked-in env names, types, defaults, and requiredness

See Environment Variables for local, production-secret, and client build behavior.