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:idroute parameter - Catch-all:
[...slug]matches the remaining path - Route groups:
(admin)/organizes files without affecting URL paths - Files starting with
_are ignored
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.tsfiles exportloaderforGETdata andactionfor 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 typesdb/schema/: optional. Split tables into separate files and re-export them fromdb/schema.tsdb/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.
// 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.
// 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
| File | Purpose |
|---|---|
vite.config.ts | Vite configuration. Must include voidPlugin(). |
void.json | Optional Void config for routing, inference, and worker settings |
tsconfig.json | TypeScript config. Extend .void/tsconfig.json for auto-generated types; run void init --tsconfig when an existing config already uses extends. |
.env | Public environment variables (committed) |
.env.local | Secret variables for local dev (gitignored) |
.env.production | Public production variables (committed) |
.env.production.local | Production secrets for local testing (gitignored) |
See Environment Variables for the full env file loading order.