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.

Nuxt ​

Nuxt has its own CLI and build system based on Nitro. Add voidPlugin() to Nuxt's Vite config for binding inference, typed DB, and migrations during development.

Setup ​

1. Create a new project ​

bash
npm create nuxt@latest my-app
cd my-app

2. Install dependencies ​

bash
npm install -D void wrangler

The wrangler dependency is needed by Nuxt to create Cloudflare platform proxy during dev.

3. Configure nuxt.config.ts ​

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 Cloudflare dev runtime and voidPlugin() migrations share Wrangler's 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:

jsonc
{
  "name": "my-app",
  "compatibility_date": "2026-02-24",
  "compatibility_flags": ["nodejs_compat", "nodejs_als"],
}

5. Deploy ​

bash
void auth login
void deploy

Using 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 ​

ts
// 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 ​

ts
import { kv } from 'void/kv';

export default defineEventHandler(async () => {
  return kv.get('app:settings');
});

Blob Storage ​

ts
import { storage } from 'void/storage';

export default defineEventHandler(async () => {
  return storage.get('avatars/user-1.png');
});

AI ​

ts
import { ai } from 'void/ai';

export default defineEventHandler(async () => {
  return ai.run('@cf/meta/llama-3.1-8b-instruct', {
    prompt: 'Summarize the latest news',
  });
});

Cron Jobs ​

ts
// crons/daily-cleanup.ts
import { defineScheduled } from 'void';

export const cron = '0 0 * * *';

export default defineScheduled(async () => {
  // runs daily at midnight
});

Queue Consumers ​

ts
// 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 ​

Void gives you a typed env layer: declare keys in env.ts, read them via import { env } from "void/env", and get schema validation at build + deploy time plus a client-leak guard that fails the build if a server-only key reaches the browser. See the env vars guide for the full feature set.

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:

ts
// 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;
});