Skip to content

Nuxt and Analog with void/nitro: missing nodejs_compat on native deploys, incomplete init notes, and test, type and size gaps #418

Closed

Description

@Brooooooklyn

These apply after #413, which adds the void/nitro module for PostgreSQL and MySQL apps.

Problem

Area What happens
a void deploy --platform cloudflare A pg/MySQL Nuxt app gets no nodejs_compat unless void.config.ts lists it
b void init The printed Nuxt and Analog config does not deploy
c Analog pg without void/nitro The build fails on pg-native before Void's hint
d CI No test runs a Nitro-built pg/MySQL Worker in workerd
e nuxi typecheck TS2307 for @schema and TS2561 for cloudflareDev
f Size Analog MySQL Workers carry 3-4 copies of mysql2

a. Native deploys can miss nodejs_compat

void deploy --platform cloudflare writes the Worker config from void.config.ts (cloudflare.compatibility_flags) plus the Nuxt preset flags. The preset adds only nodejs_als. Nothing adds nodejs_compat for pg/MySQL, but the drivers need it. The managed void deploy adds it.

The docs page sets nodejs_compat in void.config.ts, so apps that copy the docs are fine. void init writes only nodejs_als. For pg and MySQL Nuxt apps without the flag, the generated .void-wrangler.jsonc held only nodejs_als.

Nitro itself reads only wrangler.json, wrangler.jsonc or wrangler.toml, never .void-wrangler.jsonc. So every Nuxt build logs:

[nitro]  WARN  [cloudflare] Node.js compatibility is not enabled.

Nitro then uses unenv's Node stubs. void/nitro works around this only for the driver and Void's own node:async_hooks. Other server code that imports Node modules gets the stubs.

b. void init notes do not give a working config

The Nuxt note prints only nitro: { modules: ["void/nitro"] } and vite: { plugins: [voidPlugin()] }. The Analog note prints only analog({ nitro: { modules: ["nitro-cloudflare-dev", "void/nitro"] } }). Neither has preset: 'cloudflare-module' or cloudflareDev: { configPath: './.void-wrangler.jsonc' }, which the docs pages have.

Applied as printed to fresh create-nuxt and create-analog apps:

  • Nuxt dev, pg route: 500 env: Cloudflare env is unavailable. Use void runtime bindings inside ...
  • Nuxt build: Nitro preset: node-server. The uploaded Worker fails at start: No such module "unhead/server".
  • Analog build: also node-server. The Worker fails at start: No such module "void/_env".

With the preset and cloudflareDev added, both apps work in dev and on a managed deploy (60 of 60 requests ok).

c. Analog pg without void/nitro

An Analog pg app with a .server.ts page load and no void/nitro (the old docs config) fails the Nitro build before Void's runtime hint can show:

[nitro]  ERROR  Error: Cannot resolve "pg-native" from ".../node_modules/pg/lib/native/client.js" and externals are not allowed!

Nuxt pg/MySQL and Analog MySQL without the module do show the hint ("add 'void/nitro' to the Nitro modules").

d. No CI test for a Nitro-built pg/MySQL Worker

packages/void/test/unit/nitro.test.ts checks the plugin hooks (:94) and runs the request scope in Node (:115). The Nuxt and Analog playgrounds use D1. Nothing builds a Nitro cloudflare-module Worker with pg or MySQL and runs it in workerd. The load checks so far were manual.

e. nuxi typecheck errors in a fresh Nuxt 4 app

Following the docs in a fresh create-nuxt app (Nuxt 4.6.1):

server/api/users.get.ts(1,23): error TS2307: Cannot find module '@schema' or its corresponding type declarations.
nuxt.config.ts(9,5): error TS2561: Object literal may only specify known properties, but 'cloudflareDev' does not exist in type 'ResolveNuxtNitroConfig<NitroConfig>'. Did you mean to write 'cloudflare'?

The TS2307 comes from the app project. Nuxt's typed $fetch routes import server/api/* into it, and that project's paths come from Nuxt's top-level alias, not from nitro.alias. A top-level alias: { '@schema': resolve(import.meta.dirname, 'db/schema.ts') } clears it. Both errors also occur with the docs on main.

f. Several mysql2 copies in Analog MySQL Workers

Managed Worker upload sizes:

App Upload gzip mysql2 copies
Nuxt MySQL (npm) 3571.09 KiB 1236.34 KiB 3
Analog MySQL (npm) 4843.69 KiB 1578.66 KiB 3
Analog MySQL (pnpm) 5600.98 KiB 1899.53 KiB 4
Analog MySQL (pnpm), driver kept external in Vite's SSR build (prototype) 4806.03 KiB 1566.39 KiB 3

The copies are the cron/queue bundle, the migration handler and Nitro's void/db chunk. With pnpm, Analog's Vite SSR build cannot resolve mysql2 from the app root, so it also bundles the driver into the page-load chunk (users.server-*.js). Keeping it external saves about 333 KiB gzip. All sizes are under the Workers Free limit (3 MB compressed), but a growing app gets close.

Repro

  • a. void init in a Nuxt app, set database: 'pg', keep the generated void.config.ts (nodejs_als only), add void/nitro and the preset, then void deploy --platform cloudflare.
  • b. Fresh create-nuxt / create-analog app, void init, apply the printed note as is, vp dev and build.
  • c. Analog pg app with a .server.ts load that uses void/db, nitro.alias['@schema'] and no void/nitro; build.
  • e. Fresh create-nuxt app, docs config, server/api/users.get.ts importing @schema; run npx nuxi typecheck.
  • f. Build an Analog MySQL app with pnpm and count mysql2 copies in the Worker output.

Cause

  • a. packages/void/src/cli/deploy-cloudflare-static.ts:136 passes only preset.cloudflareCompatibilityFlags; packages/void/src/cli/preset.ts:125-127 gives Nuxt ['nodejs_als']. The managed path adds nodejs_compat for non-D1 dialects in packages/void/src/cli/deploy-helpers.ts:176-199. packages/void/src/cli/init.ts:1322 writes only nodejs_als. Nitro's readWranglerConfig (nitropack dist/presets/cloudflare/utils.mjs:174-176) looks only for wrangler.json, wrangler.jsonc and wrangler.toml; packages/void/src/plugin-drizzle.ts:441-442 notes this.
  • b. packages/void/src/cli/init.ts:2373-2402. On main the Nuxt note had the same gap, and Analog fell back to the generic Vite note.
  • c. Nitro bundles pg without Void's driver build, and pg/lib/native/client.js requires pg-native. The hint is in packages/void/src/runtime/db.ts:59-70, which this build never reaches.
  • d. packages/void/test/unit/nitro.test.ts; playground/nuxt and playground/analog are D1 apps.
  • e. Nuxt types server routes for the app project from nuxt.options.alias; cloudflareDev is not in Nuxt's Nitro config type.
  • f. The void/db template imports drizzle-orm/mysql2 by path (packages/void/src/plugin-drizzle.ts:18), and its bare mysql2 import is inlined by Vite's SSR build when it cannot be resolved from the app root.

Suggested fix

  • a. In the native framework deploy, add nodejs_compat for pg/MySQL as the managed path does. Have void init write it for pg/MySQL apps.
  • b. Put preset: 'cloudflare-module' and cloudflareDev in both notes, or link the framework docs page.
  • c. Add a short Analog troubleshooting note that names void/nitro.
  • d. Add one test that builds a tiny Nitro cloudflare-module app with PGlite or the fake MySQL server and runs concurrent requests in Miniflare.
  • e. Docs: use a top-level Nuxt alias for @schema, and say how to type cloudflareDev (or that the error is harmless).
  • f. For Nitro frameworks, keep the dialect's driver external in Vite's server build so Nitro uses void/nitro's shared driver bundle.

Evidence

🤖 Generated with Claude Code

https://claude.ai/code/session_0123r5HnanmW2VUrZ7VWDufH

Activity

  1. added 8 commits that reference this issue on Oct 14, 2026
    3009112
    cd26816
    7e567da
    76214c3
    a3f1768
    870b9cb
    c2d041d
    0f43659
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions