Project Structure
This page shows where each kind of file goes in an SDK project. Folder names are conventions. Put a file in the right place and the SDK connects it for you.
On this pageFind the right folder for routes, pages, jobs and more · See what each folder does · Learn which config files belong at the root
Overview
An SDK 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
- email/Inbound email handlers
- durable-objects/Durable State modules
- src/Shared app code
- public/Static assets (served as-is)
- .void/Auto-generated (gitignored)
- vite.config.tsVite config with voidPlugin()
- void.config.tsVoid project config (optional)
- .envLocal environment values
- env.tsEnvironment schema
- package.json
- tsconfig.json
routes/
File-based HTTP API endpoints, built on Hono. Each file exports one named handler per HTTP method.
- 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 the:idroute parameter - Catch-all:
[...slug]matches the remaining path - Route groups:
(admin)/groups files without changing URL paths - Files starting with
_are ignored - Environment suffix:
debug.dev.tsbuilds only in dev.metrics.prod.tsbuilds only in production
See Server Routing for the full guide.
pages/
Full-stack server-rendered pages with data loading next to each page. Adapters exist for Vue, React, Svelte and Solid.
- 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 changes. Each pairs with the page component of the same name- Layouts nest on their own and stay mounted across navigations
- Markdown pages are supported with frontmatter
See Pages Routing for the full guide.
middleware/
Global middleware that runs on every request. Number prefixes set the order.
- middleware/
- 01.logger.tsRuns first
- 02.auth.tsRuns second
Each file default-exports a defineMiddleware() handler. Use middleware for shared context that every route needs, such as auth, logging or rate limits.
db/
Drizzle schemas and SQL migrations for D1, PostgreSQL or MySQL.
- db/
- schema.tsDrizzle schema (source of truth)
- schema/Optional: split into multiple files
- migrations/
- 20260410161500_*.sql
- 20260410161501_*.sql
db/schema.ts: your Drizzle tables. This file is the source of truth for DB typesdb/schema/: optional. Split tables into files and re-export them fromdb/schema.tsdb/migrations/: generated SQL migrations. Deploys apply them in order
Create the schema with void gen model or by hand. Create migrations with void db generate.
crons/
Scheduled jobs. Each file exports a cron expression and a default defineScheduled() handler.
queues/
Queue consumers. Each file default-exports a defineQueue() handler.
email/
Inbound email handlers. The file name picks the recipient. _default.ts handles all other addresses.
durable-objects/
Durable State modules. Each file default-exports a defineDurableState() definition.
src/
Shared code such as components, utilities and types. This folder has no special rules. Organize it as you like.
public/
Static assets, served as-is from the root path. Vite does not process these files.
.void/
Generated types and local dev state. Git ignores this folder. Run void prepare to create the types. vite dev and vite build also update them.
Config files
| File | Purpose |
|---|---|
vite.config.ts | Vite configuration. Must include voidPlugin(). |
void.config.ts | Optional SDK 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 | Local development values only (gitignored; never deployed) |
env.ts | Checked-in env names, types, defaults, and requiredness |
See Environment Variables for local values, production secrets and client builds.