Nuxt
Use Void with Nuxt for resource detection, typed database queries, and migrations. Nuxt keeps its own build and Cloudflare integration; Void plugs into its Vite configuration.
Setup
1. Create a new project
npm create nuxt@latest my-app
cd my-app2. Install dependencies
npm install -D voidVoid includes the Cloudflare tooling used by Nuxt's platform proxy during development.
3. Configure nuxt.config.ts
import { resolve } from 'node:path';
import { voidPlugin } from 'void';
export default defineNuxtConfig({
nitro: {
preset: 'cloudflare-module',
alias: {
// Nitro has its own bundler that doesn't use Vite aliases.
// Duplicate @schema here so Nitro can resolve it.
'@schema': resolve(__dirname, 'db/schema.ts'),
},
},
vite: { plugins: [voidPlugin()] },
});By default, Nuxt's Cloudflare development runtime and voidPlugin() migrations share local state at .wrangler/state/v3, so no extra persistence configuration is required.
4. Create wrangler.jsonc
voidPlugin() auto-syncs inferred bindings into this file on dev startup:
{
"name": "my-app",
"compatibility_date": "2026-02-24",
"compatibility_flags": ["nodejs_compat", "nodejs_als"],
}5. Deploy
void auth login
void deployUsing Void Platform Features
Most Void platform features work with Nuxt. Use them in server routes, API handlers, and middleware:
Void-managed auth is not supported in framework mode yet. Use Better Auth's official Nuxt integration directly for now.
Database
// server/api/users.get.ts
import { db } from 'void/db';
import { users } from '@schema';
export default defineEventHandler(async () => {
return db.select().from(users);
});⚠️ Nuxt limitation
Nuxt uses Nitro, which bundles server routes outside of Vite's plugin pipeline. The schema cannot be injected into the db instance, so db.query.* relational queries are not available in Nuxt. Use the standard query builder API (db.select().from(table)) instead.
KV Storage
import { kv } from 'void/kv';
export default defineEventHandler(async () => {
return kv.get('app:settings');
});Blob Storage
import { storage } from 'void/storage';
export default defineEventHandler(async () => {
return storage.get('avatars/user-1.png');
});AI
import { ai } from 'void/ai';
export default defineEventHandler(async () => {
return ai.run('@cf/meta/llama-3.3-70b-instruct-fp8-fast', {
prompt: 'Summarize the latest news',
});
});Cron Jobs
// crons/daily-cleanup.ts
import { defineScheduled } from 'void';
export const cron = '0 0 * * *';
export default defineScheduled(async () => {
// runs daily at midnight
});Queue Consumers
// queues/emails.ts
import { defineQueue } from 'void';
export default defineQueue<{ to: string; subject: string }>(async (batch) => {
for (const msg of batch.messages) {
// process each message
msg.ack();
}
});Environment Variables
Declare environment variables in env.ts, then read them with import { env } from "void/env". Void supplies types, checks values during build and deploy, and stops the build if client code references a server-only key. See Environment Variables.
void/env replaces useRuntimeConfig() and event.context.cloudflare.env for env-var access. Keep event.context.cloudflare.env around when you need raw binding access (D1, KV, R2, etc.), and useRuntimeConfig() when you need non-env runtime config.
Accessing Bindings Directly
You can also access raw Cloudflare bindings via Nitro's event context:
// server/api/users.get.ts
export default defineEventHandler(async (event) => {
const { DB } = event.context.cloudflare.env;
const { results } = await DB.prepare('SELECT * FROM users').all();
return results;
});