Supported App Types
Void supports three types of apps:
- Void apps: Vite apps powered by Void's framework layer, including API routes, pages mode, auth, crons, and queues
- Meta frameworks: TanStack Start, React Router, SvelteKit, Nuxt, and Astro
- Static sites: SPAs, sites built with tools like VitePress, or any directory of static files
The type is auto-detected from your project structure, or you can set it explicitly in void.config.ts.
Void Apps
In a Void app, Void handles server routing and deployment. Use React, Vue, Svelte, or Solid for server-rendered pages, or build a frontend with any library that works with Vite.
A Void app can be API-only (just routes/), a SPA + API (frontend in src/ with API routes), or full-stack with pages mode (server-rendered pages in pages/ with co-located data loading):
- pages/Server-rendered pages
- index.tsx
- users/
- [id].tsx
- [id].server.ts
- routes/API endpoints
- api/
- hello.ts
- db/Schema and migrations
- middleware/
- crons/
- queues/
- vite.config.ts
- void.json
Void serves API routes, page rendering, and optional custom SSR alongside static assets. Resources such as D1, KV, and R2 are inferred from your code and provisioned when you deploy.
Void apps can also use output: 'static' to pre-render all pages at build time. That gives you a fully static site that can be deployed anywhere, with no Cloudflare Worker required.
Deploy: void deploy builds the app, provisions resources, applies migrations, and uploads it to your saved Cloudflare or Void target. See Deployment for setup.
Meta Frameworks
Void supports deploying Vite-based meta-framework apps with void deploy. The framework owns routing and SSR. Void handles binding inference, typed DB queries, migrations, and deployment.
| Framework | Detected from package | Setup guide |
|---|---|---|
| TanStack Start | @tanstack/react-start | Guide |
| React Router v7 | @react-router/dev | Guide |
| SvelteKit | @sveltejs/kit | Guide |
| Nuxt | nuxt | Guide |
| Analog | @analogjs/platform | Guide |
| Astro | astro | Guide |
Add voidPlugin() to the framework's Vite config to get binding inference, typed DB generation, migration management, cron jobs, queues, and caching. Void-managed auth is not supported in framework mode; use Better Auth's official integration for your framework. See the Meta Frameworks Integration for supported features and setup guides.
Pre-built Static Sites
Any project that produces static files, whether that is an SPA, a static site, or a plain directory. Void serves the assets without requiring application code.
SPAs (client-side single-page apps) serve index.html with a 200 status for paths that match no file, so client-side routing works out of the box. On a Void platform, missing files under the hashed assets folder (/assets/) return 404 instead. Detected when vite is a dependency and no backend files exist.
Static sites (static site generators like VitePress, Docusaurus, or any pre-built directory) produce per-page HTML files. Detected when a known SSG is a dependency, or when using the --dir flag.
At the edge, the resolution order is:
- Exact file path (
/styles.css→styles.css) - Nested index (
/about→about/index.html) 404.htmlwith status 404 (if the file exists)- Plain 404 response
Deploy: void deploy or void deploy --dir <path> uploads static files directly. Assets are served from the edge with automatic caching.
Adding a backend to a static site
If you add API routes to a static site generator, tell Void whether to deploy the backend too. Auto-detection sees both the SSG dependency and backend files, and stops until you set inference.appType.
To deploy both, set appType to "void" and build the static site before the Void app:
import { defineConfig } from 'void/config';
export default defineConfig({
inference: {
appType: 'void',
build: 'vitepress build && vite build',
},
});// vite.config.ts
import { defineConfig } from 'vite';
import { voidPlugin } from 'void';
export default defineConfig({
plugins: [voidPlugin()],
// The SSG's output becomes the static assets of the Void build.
publicDir: '.vitepress/dist',
});vitepress build emits the site, then vite build copies publicDir into dist/client and emits the worker into dist/ssr. Keep voidPlugin() in the root vite.config.ts only — not in the generator's own config (e.g. .vitepress/config.ts).
The Worker handles unmatched requests. Set routing.notFound to serve the generator's 404.html for those requests:
{ "routing": { "notFound": "404-page" } }To deploy only the static output, set:
{ "inference": { "appType": "static" } }Explicit Configuration
To lock the app type and skip auto-detection, set inference.appType in void.config.ts:
{
"inference": {
"appType": "static",
"outputDir": ".vitepress/dist"
}
}inference.appType:"void","framework","spa", or"static"inference.outputDir: output directory for static app types (relative to project root, defaults to"dist")