Skip to content
brought to you byVoidZero
Private Beta:Void is currently in Private Beta. We do not recommend using it for mission-critical production workloads yet. Please back up your data regularly.

Config

Config File Format

Use this page as the exact reference for void.json. If you are still learning how the pieces fit together, start in the guide first and come back here when you need field-by-field details.

Project-level configuration lives in a void.json file at the project root. Most fields are optional. Cloudflare-targeted apps must pin a Workers compatibility_date in worker.compatibility_date or in a supported wrangler fallback file (wrangler.jsonc or wrangler.json). If no date is configured, Void writes the latest known-good date to void.json so future runs stay explicit and stable.

json
{
  "$schema": "./node_modules/void/schema.json",
  "target": "cloudflare",
  "auth": {
    "providers": ["email", "github", "google"]
  },
  "routing": {
    "revalidate": { "/": 60, "*": 30 },
    "headers": {
      "/assets/*": ["Cache-Control: public, max-age=31536000, immutable"],
      "/*": ["X-Frame-Options: DENY", "X-Content-Type-Options: nosniff"]
    }
  },
  "inference": {
    "bindings": { "db": true, "kv": false },
    "appType": "spa",
    "outputDir": "dist"
  },
  "worker": {
    "compatibility_date": "2025-12-01",
    "compatibility_flags": ["nodejs_compat"]
  }
}

Add the $schema field for autocomplete and validation in your editor.

Fields

auth

High-level Better Auth configuration.

Use auth.providers to select which built-in auth providers Void should enable by default. Include "email" for email/password auth. Social providers read credentials from AUTH_<PROVIDER>_CLIENT_ID and AUTH_<PROVIDER>_CLIENT_SECRET.

json
{
  "auth": {
    "providers": ["email", "github", "google", "discord"]
  }
}

If auth is omitted but auth is active via imports, Void enables email/password only. For provider-specific options, scopes, plugins, or custom OAuth flows, use a root auth.ts with defineAuth(...).

Supported values for auth.providers:

  • email
  • apple
  • atlassian
  • cognito
  • discord
  • dropbox
  • facebook
  • figma
  • github
  • gitlab
  • google
  • huggingface
  • kakao
  • kick
  • line
  • linear
  • linkedin
  • microsoft
  • naver
  • notion
  • paybin
  • paypal
  • polar
  • railway
  • reddit
  • roblox
  • salesforce
  • slack
  • spotify
  • tiktok
  • twitch
  • twitter
  • vercel
  • vk
  • zoom

database

Database backend. Omit for D1/SQLite (default). Set to "pg" for PostgreSQL via Hyperdrive.

json
{
  "database": "pg"
}
ValueDescription
(omitted)D1 (SQLite), fully managed by Void with no extra config
"pg"PostgreSQL via Hyperdrive; bring your own database

When using "pg":

  • Add DATABASE_URL to .env.local for local development
  • Import schema helpers from void/schema-pg instead of void/schema-d1
  • void/db connects via Hyperdrive in production, direct connection locally
  • void gen model generates pgTable with serial, timestamp, etc.

Site-wide HTML <head> defaults for pages mode. Sets a title template, default meta tags, links, scripts, and HTML/body attributes. Per-page head() exports and middleware defaults merge on top of these with clear precedence: page > middleware > config.

FieldTypeDescription
titlestringDefault page title (overridden by page head())
titleTemplatestringWraps the resolved title. %s is replaced with the page title.
metaArray<object>Default <meta> tags (deduped by name/property, page wins)
linkArray<object>Default <link> tags (concatenated: config, middleware, page)
scriptArray<object>Default <script> tags (concatenated: config, middleware, page)
htmlAttrsRecord<string, string>Attributes on <html> (shallow merge, page wins)
bodyAttrsRecord<string, string>Attributes on <body> (shallow merge, page wins)
json
{
  "head": {
    "titleTemplate": "%s | My Site",
    "htmlAttrs": { "lang": "en" },
    "meta": [
      { "charset": "utf-8" },
      { "name": "viewport", "content": "width=device-width, initial-scale=1" }
    ],
    "link": [{ "rel": "icon", "href": "/favicon.svg" }]
  }
}

See Head Management for the full merge behavior, HeadDescriptor shape, and per-page usage.

output

Output mode. Controls the default rendering strategy for pages.

ValueDefault prerenderPer-page overridePrerender timing
"server" (default)falseexport const prerender = trueDeploy-time (platform ISR)
"static"trueexport const prerender = falseBuild-time (vite build)

When set to "static", all pages are prerendered at build time as static HTML files written to dist/client/. Individual pages can opt out with export const prerender = false. Dynamic pages (with route params) without a getPrerenderPaths() export are implicitly not prerendered.

When omitted or set to "server", pages are server-rendered on request. Individual pages can opt into deploy-time prerendering with export const prerender = true.

json
{ "output": "static" }

remote

Use remote D1/KV/R2 bindings during local development instead of local miniflare. When enabled, the Void plugin replaces local bindings with proxy-backed versions that forward operations to your deployed project's real resources via the Void proxy.

json
{ "remote": true }

Requirements:

  • Must be logged in (void auth login)
  • Must have a linked project (void project link)
  • Only affects D1 (DB), KV (KV), and R2 (STORAGE) bindings

You can also enable remote mode via the VOID_REMOTE=1 environment variable without modifying void.json:

bash
VOID_REMOTE=1 pnpm dev

sandbox

Enable and configure Cloudflare Sandboxes for Void apps. Importing from void/sandbox enables this automatically; set sandbox when you need custom container settings.

json
{
  "sandbox": {
    "image": "./Dockerfile.sandbox",
    "platformImage": "registry.example.com/acme/sandbox:latest",
    "instanceType": "lite",
    "maxInstances": 2
  }
}
FieldTypeDefault
bindingstringSANDBOX
classNamestringSandbox
containerNamestringvoid-sandbox
imagestringBundled @cloudflare/sandbox Dockerfile
imageBuildContextstringDirectory of image
platformImagestringMatching sandbox SDK registry image
instanceTypestringlite on Void deploy
maxInstancesnumber20 on Void deploy

Sandbox support currently applies to Void apps on the Cloudflare target. void deploy supports registry images. If sandbox.image is a custom local Dockerfile path, set sandbox.platformImage to the pushed image that the platform should run.

target

Deploy target runtime. Defaults to "cloudflare".

ValueDescription
"cloudflare"Cloudflare Workers (default), with full platform features
"node"Node.js, using @hono/node-server
"bun"Bun, using Bun.serve()
"deno"Deno, using Deno.serve()

Non-CF targets disable CF bindings (void/db, void/kv, void/auth, void/storage, void/ai, void/sandbox, void/env, void/ws). Importing any of these with a non-CF target produces a compile-time error. File-based routing, middleware, and void/client all work normally.

json
{ "target": "node" }

worker

Curated Cloudflare Workers configuration. Cloudflare-targeted apps require an explicit compatibility_date here unless it is provided by a supported wrangler fallback file. If no date is configured, Void writes the latest known-good date here. Binding arrays such as d1_databases, kv_namespaces, and r2_buckets are not allowed here because Void manages bindings through inference and inference.bindings. If you need custom bindings with real IDs, use a wrangler.json and wrangler deploy.

FieldTypeDescription
compatibility_datestringCloudflare Workers compatibility date
compatibility_flagsstring[]Cloudflare Workers compatibility flags
json
{
  "worker": {
    "compatibility_date": "2025-12-01",
    "compatibility_flags": ["nodejs_compat"]
  }
}

routing

Routing and edge configuration for headers, redirects, rewrites, and caching.

routing.headers

Custom response headers for static assets. Keys are URL patterns, values are arrays of "Name: value" strings. See Custom Headers for details.

json
{
  "routing": {
    "headers": {
      "/assets/*": ["Cache-Control: public, max-age=31536000, immutable"],
      "/*": ["X-Frame-Options: DENY", "X-Content-Type-Options: nosniff"]
    }
  }
}

routing.redirects

URL redirects. Keys are source URL patterns, values are destination strings (302 default) or objects with to and optional status (301, 302, 303, 307, 308). See Redirects for details.

json
{
  "routing": {
    "redirects": {
      "/old": "/new",
      "/blog/*": { "to": "/posts/:splat", "status": 301 }
    }
  }
}

routing.rewrites

URL rewrites. Keys are source URL patterns, values are destination paths. Serves content from the destination without changing the browser URL. See Rewrites for details.

json
{
  "routing": {
    "rewrites": {
      "/": "/en",
      "/docs/*": "/en/docs/:splat"
    }
  }
}

Destinations use the RewriteDestination shape — typed route patterns plus string, so known routes autocomplete while dynamic paths remain accepted. See Programmatic rewrites in middleware for the trade-off and performance notes.

routing.fallbacks

Fallback rewrites. Same shape as rewrites, but rules only fire when no static asset or route matched the request (i.e. the request would otherwise 404). Useful for SPA shells or default-locale catch-alls that shouldn't pre-empt real routes. See Rewrites → Fallbacks for details.

json
{
  "routing": {
    "fallbacks": {
      "/*": "/index.html"
    }
  }
}

routing.revalidate

ISR revalidation TTL in seconds, either globally or per path. See Revalidation for details.

json
{
  "routing": {
    "revalidate": {
      "/": 60,
      "/docs/*": 31536000,
      "*": 30
    }
  }
}

routing.revalidateQueryAllowlist

Query parameters that participate in ISR variant keys for dispatch rewrites. Keys are source URL patterns, values are query parameter names to keep. When omitted, rewritten ISR cache keys drop every incoming query parameter to avoid unbounded cache fanout.

json
{
  "routing": {
    "revalidateQueryAllowlist": {
      "/search": ["q"],
      "/products/*": ["variant", "currency"],
      "*": []
    }
  }
}

routing.prerender

Paths to prerender as static HTML at deploy time. Each path must start with /. See Edge Prerendering for details.

json
{
  "routing": {
    "prerender": ["/", "/about", "/pricing"]
  }
}

inference

Configuration for build-time inference, including how Void detects your app type, bindings, and build process.

inference.bindings

Explicitly control inferred Cloudflare bindings. If omitted, bindings are automatically inferred by scanning your source files for binding usage. If provided, explicit values take precedence and inference is skipped entirely.

Each binding accepts true (use default name), false (disable), or a string (custom binding name):

json
{ "inference": { "bindings": { "db": true, "kv": false, "storage": "MY_BUCKET" } } }
KeyDefault BindingTypeCustom Name
dbDBD1Database"db": "MY_DB"
kvKVKVNamespace"kv": "MY_KV"
storageSTORAGER2Bucket"storage": "MY_BUCKET"
aiAIAiBoolean only

Custom names are used in the deploy manifest and in wrangler binding sync for local dev.

inference.build

Override the build command. Useful for frameworks with their own CLIs (Nuxt, Astro) or static apps with custom build scripts. If omitted, the CLI uses the detected default build command for the current app type.

json
{ "inference": { "build": "nuxt build --preset cloudflare-module" } }

inference.scanDirs

Override which directories are scanned for binding inference. Paths are relative to the project root. Replaces the default directories for the current mode.

json
{ "inference": { "scanDirs": ["src", "lib", "workers"] } }

inference.appType

App type. If omitted, auto-detected on first deploy. See Supported App Types.

  • "void": worker plus assets, including API routes, SSR, and jobs
  • "framework": a meta-framework app such as TanStack Start, React Router, SvelteKit, Nuxt, or Astro
  • "static": fully rendered HTML files from VitePress, plain HTML, or external tools. Non-matching paths return 404.html or a 404 response.
  • "spa": static output with SPA fallback. Non-file paths fall back to index.html with a 200 status so client-side routing works out of the box.

inference.outputDir

Output directory for static deploys, relative to the project root. Only relevant when inference.appType is "spa" or "static". Defaults to "dist".