Why Prisma's `createRequire` failed under webpack
Prisma's WASM query compiler failed in a Next.js 15 app because webpack transformed its `node:module` import.
The generated client worked in Node.js but failed after Next.js bundled it.
TL;DR
In a Next.js 15 ESM app using Prisma's prisma-client generator, driverAdapters, and queryCompiler, webpack transformed the generated client's node:module import. The same code worked in Node.js. Using __non_webpack_require__ kept those imports out of webpack, and Prisma 6.11.0 later shipped an upstream fix.
On this page
I reproduced createRequire is not a function in a demo Next.js 15 app using Prisma Postgres, Driver Adapters, and the new prisma-client generator.
The generated client failed while loading Prisma’s WebAssembly query compiler:
⨯ TypeError: createRequire is not a function The app used default webpack and ESM through "type": "module". There was no Edge runtime, middleware, or custom webpack configuration involved.
The same generated code worked in plain Node.js. It failed after webpack bundled it.
Prisma fixed this in 6.11.0. If you have the same error, check your Prisma version before patching generated code.
How Prisma loads the query compiler
The new prisma-client generator writes TypeScript into your codebase instead of generating a client inside node_modules.
With queryCompiler enabled, that code loads Prisma’s WebAssembly query compiler from @prisma/client/runtime. Driver Adapters then pass the resulting SQL to a JavaScript database driver such as @prisma/adapter-pg.
My schema was minimal:
generator client {
provider = "prisma-client"
output = "../lib/.generated/prisma"
previewFeatures = ["driverAdapters", "queryCompiler"]
} The generated client crashed here:
getQueryCompilerWasmModule: async () => {
const { readFile } = await import('node:fs/promises')
const { createRequire } = await import('node:module')
const require = createRequire(import.meta.url)
// ^^^^^^^^^^ ⨯ TypeError: createRequire is not a function
const wasmModulePath = require.resolve(
"@prisma/client/runtime/query_compiler_bg.postgresql.wasm"
)
const wasmModuleBytes = await readFile(wasmModulePath)
return new globalThis.WebAssembly.Module(wasmModuleBytes)
} Node.js can run this sequence as written:
- import
node:module - call
createRequire(import.meta.url)because the file is ESM - use
require.resolve()to find the.wasmfile on disk - read the bytes and construct
WebAssembly.Module
Two issues had already reported the same failure: prisma#27049 and prisma#27343. Neither included a workaround, so I traced the generated code path.
What webpack changed
I assumed await import('node:module') would retain its Node.js behavior inside bundled server code. Webpack analyzed and transformed the import during compilation. At runtime, createRequire was no longer Node’s function.
Using import.meta.resolve would not have avoided the problem. It expressed the same intent more directly, but webpack did not support it.
Webpack has a related open bug for incorrect handling of createRequire and require.
I needed to load the .wasm file without webpack rewriting the Node.js calls.
Importing the WASM file
My first idea was to remove createRequire entirely and import the .wasm file as a module:
getQueryCompilerWasmModule: async () => {
return await import(
"@prisma/client/runtime/query_compiler_bg.postgresql.wasm"
)
} Webpack rejected that immediately:
Module parse failed: Unexpected character '' (1:0)
The module seem to be a WebAssembly module, but module is not flagged
as WebAssembly module for webpack.
BREAKING CHANGE: Since webpack 5 WebAssembly is not enabled by default
and flagged as experimental feature.
You need to enable one of the WebAssembly experiments via
'experiments.asyncWebAssembly: true' (based on async modules) or
'experiments.syncWebAssembly: true' (like webpack 4, deprecated). Webpack 5 keeps WebAssembly support behind an opt-in experiment.
Enabling asyncWebAssembly
So I enabled it:
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: (config, { isServer: _ }) => {
config.experiments = {
...config.experiments,
asyncWebAssembly: true,
}
return config
},
}
export default nextConfig Webpack then failed on an import embedded in the binary:
Module not found: Can't resolve './query_compiler_bg.js' Webpack was now reading the .wasm file, but the binary imported ./query_compiler_bg.js. Prisma publishes provider-specific files such as query_compiler_bg.postgresql.js, so the requested file did not exist.
I confirmed the embedded import with strings:
strings node_modules/@prisma/client/runtime/query_compiler_bg.postgresql.wasm \
| grep "query_compiler_bg.js" \
| head -1
# --> ./query_compiler_bg.js The runtime directory contained provider-specific files:
ls node_modules/@prisma/client/runtime/query_compiler_bg* query_compiler_bg.mysql.js
query_compiler_bg.mysql.mjs
query_compiler_bg.mysql.wasm
query_compiler_bg.postgresql.js
query_compiler_bg.postgresql.mjs
query_compiler_bg.postgresql.wasm
query_compiler_bg.sqlite.js
query_compiler_bg.sqlite.mjs
query_compiler_bg.sqlite.wasm
query_compiler_bg.sqlserver.js
query_compiler_bg.sqlserver.mjs
query_compiler_bg.sqlserver.wasm The mismatch comes from two build steps. The wasm-bindgen build script emits an import for query_compiler_bg.js. Prisma’s client generation logic later renames the published artifacts by database provider. The binary expects the generic filename, while the package contains the provider-specific one.
Rewriting the filename inside the binary
I had isolated the embedded filename, so I wrote a script to replace it inside the .wasm file:
#!/bin/bash
# Requirements: cargo binstall wasm-tools
FILE_IN="node_modules/@prisma/client/runtime/query_compiler_bg.postgresql.wasm"
FILE_OUT="node_modules/@prisma/client/runtime/query_compiler_bg.postgresql.patched.wasm"
ORIG="query_compiler_bg.js"
REPL="query_compiler_bg.postgresql.js"
wasm-tools print "${FILE_IN}" \
| sed "s/${ORIG}/${REPL}/g" \
| wasm-tools parse -o "${FILE_OUT}"
echo "✅ All occurrences replaced."
wasm-tools validate "${FILE_OUT}" Then I pointed the generated code at the patched artifact:
getQueryCompilerWasmModule: async () => {
const queryCompilerWasm = await import(
"@prisma/client/runtime/query_compiler_bg.postgresql.patched.wasm"
)
return queryCompilerWasm
} The patched import failed with a different type error:
⨯ [TypeError: WebAssembly.Instance(): Argument 0 must be a WebAssembly.Module] The filename was no longer the problem. Webpack’s asyncWebAssembly support compiles and instantiates the module, then returns an object containing its exports:
{
memory: Memory [WebAssembly.Memory] {},
__wbg_querycompiler_free: [Function: 1553],
querycompiler_new: [Function: 3660],
querycompiler_compile: [Function: 3578],
querycompiler_compileBatch: [Function: 3579],
__wbindgen_malloc: [Function: 3320],
__wbindgen_realloc: [Function: 3428],
__wbindgen_exn_store: [Function: 4342],
__externref_table_alloc: [Function: 899],
__wbindgen_export_4: Table [WebAssembly.Table] {},
__externref_table_dealloc: [Function: 2543],
__wbindgen_start: [Function: 60]
} That return value works when an application wants to call the exported functions. Prisma’s WasmQueryCompilerLoader expects the raw WebAssembly.Module so it can instantiate the compiler with its own imports and lifecycle.
The patched binary still returned the wrong type. prisma#23536 reported the same WebAssembly.Instance mismatch with Cloudflare Pages and Remix. In both cases, Prisma expected a module and the bundler returned an instance-like export object.
Bypassing webpack
Prisma’s original loading path already resolved the file, read its bytes, and constructed a WebAssembly.Module. Only the two Node.js imports needed to bypass webpack.
Webpack exposes __non_webpack_require__ for calls that must remain runtime require calls:
getQueryCompilerWasmModule: async () => {
const { readFile } = __non_webpack_require__('node:fs/promises')
const { createRequire } = __non_webpack_require__('node:module')
const _require = createRequire(import.meta.url)
const wasmModulePath = _require.resolve(
"@prisma/client/runtime/query_compiler_bg.postgresql.wasm"
)
const wasmModuleBytes = await readFile(wasmModulePath)
return new globalThis.WebAssembly.Module(wasmModuleBytes)
} With those two calls bypassing webpack, Prisma loaded the query compiler.
Why this works:
- Next.js server code still runs in Node.js, so
requireexists at runtime __non_webpack_require__tells webpack not to parse or transform thatrequire- file resolution, byte loading, and
WebAssembly.Moduleconstruction continue unchanged
The upstream fix
Webpack later added support for using /* webpackIgnore: true */ with require.resolve():
(
typeof __non_webpack_require__ === 'function'
? __non_webpack_require__
: require
).resolve(
/* webpackIgnore: true */
'@prisma/client/runtime/query_compiler_bg.postgresql.wasm'
) Prisma adopted that form, and the fix shipped in Prisma 6.11.0.
References
- prisma#27049:
TypeError: createRequire is not a functionwith the query compiler - prisma#27343: generated
prisma-clientcode can’t be bundled by Next.js - prisma#23536: same
WebAssembly.Instancetype mismatch on Cloudflare Pages + Remix - webpack#19607: incorrect handling of
createRequireandrequire - webpack#16693:
import.meta.resolvesupport - webpack#19201:
/* webpackIgnore: true */forrequire.resolve