Your Vercel deployment log stops on this line:
Module not found: Can't resolve 'encoding' in '/vercel/path0/node_modules/cross-fetch/node_modules/node-fetch/lib'
The build fails before the app ever deploys. You'll typically hit it in a Next.js app that uses the Supabase JS client, because @supabase/supabase-js transitively depends on cross-fetch. The error appears during the Next.js build process — either locally with next build or in Vercel's CI logs — and the behavior is the same across Next.js 13+, Vercel deployments, and projects using @supabase/supabase-js. It does not occur in pure Node.js environments where encoding is more likely to be present.
The short version: cross-fetch depends on node-fetch, which requires the encoding package, but encoding isn't installed and Next.js strips Node.js polyfills. Install encoding, add a Webpack fallback, and pin cross-fetch to v4.1.0+ so it stops pulling in node-fetch@2.
The dependency chain: cross-fetch → node-fetch@2 → encoding
The root cause is a mismatch between Node.js runtime expectations and Next.js's browser-first build strategy. cross-fetch (a popular polyfill for window.fetch) depends on node-fetch, which in turn uses the encoding package to handle non-UTF-8 text encodings — a Node.js-specific feature. When Next.js bundles your code for the browser, it strips out Node.js built-ins like buffer, process, and encoding unless explicitly configured.
This becomes a problem because node-fetch@2.x (still used by older cross-fetch versions) imports encoding unconditionally in its source code. The import path looks something like:
// node-fetch/lib/fetch.js (v2.6.7)
const { TextDecoder, TextEncoder } = require('encoding');
But encoding is not installed — and Next.js's Webpack config does not include encoding in its polyfill set by default. When Webpack attempts to resolve the require('encoding') call inside node-fetch@2.x, it cannot find the package in the dependency tree (unless explicitly added to package.json), and the build fails with the module resolution error above.
This is not a bug in Supabase or cross-fetch — it's a known limitation of using Node.js polyfills in a browser-oriented framework like Next.js.
Why it fails on Vercel but not on your machine
Vercel's build environment enforces stricter module resolution than local dev servers. Locally, next dev may cache or skip some checks, but next build (and Vercel's CI) will catch the missing dependency. That's why the first sign of trouble is often a red deployment, not a local error — and why running next build locally is the fastest way to reproduce it before pushing.
Two package.json changes that resolve it
The fix has three parts: install encoding, configure Webpack to polyfill Node.js built-ins (covered in the next section), and ensure cross-fetch uses a version that doesn't pull in node-fetch@2. The dependency side takes two lines:
{
"dependencies": {
"encoding": "^0.1.13",
"cross-fetch": "^4.1.0"
}
}
This addresses the cause because encoding satisfies the runtime dependency, and cross-fetch@4.1.0+ uses node-fetch@3, which no longer requires encoding — it relies on the global TextEncoder/TextDecoder APIs available in modern browsers and Node.js 17+.
Concretely:
- Open
package.json. - Add
"encoding": "^0.1.13"todependencies. - Update
"cross-fetch"to"^4.1.0"(or higher, as of 2026, v4.1.0 is the latest stable). - Run
npm installoryarn install. - Restart your dev server with
next devor runnext build.
If you're using Yarn, ensure you run yarn install — not just yarn add — to avoid version conflicts in the lockfile.
Is encoding safe to ship? Yes — it's a small, well-maintained package (20+ years old) used by many Node.js libraries. But in browser bundles, it's better to disable it via Webpack (encoding: false), since modern browsers have native TextEncoder. That's the next section.
If your app only runs in Node.js (e.g., server-side rendering), installing encoding alone may suffice. For full-stack Next.js apps, you must also configure Webpack to avoid client-side bundle errors.
encoding installed, Webpack still failing: check resolve.fallback
Sometimes encoding is present, but Next.js's Webpack configuration still excludes it due to strict externals or resolve.fallback settings. This happens if you've customized next.config.js.
To diagnose, check next.config.js for:
// next.config.js
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.fallback = {
...config.resolve.fallback,
fs: false,
net: false,
tls: false,
};
}
return config;
},
};
If encoding is missing from fallback, add it:
// next.config.js
module.exports = {
webpack: (config, { isServer }) => {
config.resolve.fallback = {
...config.resolve.fallback,
encoding: false, // ← explicitly disable polyfill for encoding
};
return config;
},
};
Why false? Because encoding is only needed at runtime in Node.js environments (like server-side rendering), not in the browser. Setting it to false tells Webpack to ignore it in client bundles, avoiding the error while keeping SSR safe.
When @supabase/realtime pulls its own cross-fetch
If you're using Supabase's Realtime client (@supabase/realtime-js), it may pull in cross-fetch as a transitive dependency, bypassing your top-level package.json resolution. This causes version mismatches: your root cross-fetch is v4, but a nested copy is still on the old line.
To fix, add a resolutions field in package.json:
{
"resolutions": {
"cross-fetch": "^4.1.0"
}
}
Then run npx npm-check-resolutions to enforce the override and reinstall dependencies.
Confirming the build is clean
Run:
npm run build
You should see:
✓ Ready in X.Xs
✓ Creating an optimized production build
✓ Compiled successfully
Instead of the Module not found: Can't resolve 'encoding' error. Once the local build passes, the Vercel build will pass too — the CI runs the same next build step.
A next.config.js that prevents the whole class of errors
Next.js optimizes for the browser by default, stripping Node.js polyfills unless explicitly requested. The encoding package is one of many Node.js-specific modules that don't exist in browsers — others include buffer, process, and stream. For projects that need broader Node.js core API coverage in the browser, the node-polyfills Webpack plugin automatically maps Node built-ins (like crypto, path, and stream) to browser-compatible shims, though for this specific case a targeted resolve.fallback entry is enough.
Two practices keep this from recurring:
Pin fetch polyfills to modern versions. Avoid
cross-fetch@2.x— it depends onnode-fetch@2, which requiresencoding. Usecross-fetch@4.1.0+, which usesnode-fetch@3and relies on nativeTextEncoder/TextDecoder.Configure Webpack polyfills explicitly. In
next.config.js, always includeencoding: falseinresolve.fallbackfor client bundles. This tells Webpack to skip polyfilling it in the browser, avoiding the resolution error.
Here's a production-ready next.config.js snippet:
// next.config.js
const nextConfig = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.fallback = {
...config.resolve.fallback,
fs: false,
net: false,
tls: false,
encoding: false,
};
}
return config;
},
};
module.exports = nextConfig;
With encoding installed, the Webpack fallback configured, and cross-fetch pinned to a modern version, the deployment builds cleanly and stays that way. I cover this pattern — along with Supabase-specific optimizations like connection pooling and environment variable handling — in Deploying Next.js + Supabase to Production.
Related
- Fix Next.js Module Not Found After Deploy or Production Build
- Next.js Env Variables Not Working on Vercel: 5 Fixes (2026)
- Supabase Connection Pooling with PgBouncer on Vercel Serverless
- Deploying Next.js + Supabase to Production
Originally published at https://www.iloveblogs.blog
Top comments (0)