serverExternalPackages
Keep a dependency out of the server bundle so Node loads it with require at runtime.
serverExternalPackages?: string[] // default: []- Added in Next.js v15.0.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$serverExternalPackagesoptional | string[]= [] | Package names to exclude from Server Component and Route Handler bundling. Each listed package is loaded with native Node.js require at runtime instead. |
Errors
next build throws at start if a package appears in both serverExternalPackages and transpilePackages.
Changelog
- PHP v15.0.0Moved from experimental to stable and renamed from serverComponentsExternalPackages to serverExternalPackages.
Dependencies used inside Server Components and Route Handlers are bundled by Next.js. Bundling breaks packages that do things a bundler cannot follow: loading a .node binary, resolving files relative to __dirname, or calling require() with a computed path. Listing the package here leaves the import alone so Node resolves it from node_modules at runtime.
When to reach for it
Reach for it when a server-only dependency builds fine but fails at runtime with a missing binary, a missing file, or a module that resolved to undefined. Next.js already opts out a long list of popular packages automatically — sharp, @prisma/client, better-sqlite3, mongodb, pino, playwright and others — so check the shipped list before adding an entry.
What trips people up
- The package must exist in
node_moduleswherever the app runs. Withoutput: 'standalone'or a Docker image that prunes dev dependencies, an externalized package that file tracing missed becomes a runtimeMODULE_NOT_FOUND. - It has no effect on client bundles — a package imported from a Client Component is still bundled for the browser.
- A package cannot be listed here and in
transpilePackages; that combination fails the build immediately.
Example
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
serverExternalPackages: ['@acme/ui'],
}
export default nextConfigWhen to use it
- Fix a server-only package that ships a native .node binary and crashes once bundled.
- Keep an ORM or logger that reads files relative to __dirname working after a build.
- Stop a package that calls require() with a computed path from resolving to undefined at runtime.
Frequently asked questions
What replaced serverComponentsExternalPackages?
serverExternalPackages replaced it in Next.js 15.0.0, when the option moved out of experimental to the top level of next.config. The behavior is the same; only the name and placement changed.
Why does my package still fail after adding it to serverExternalPackages?
Most often the package is no longer being copied into the deployment — externalizing it means Node resolves it from node_modules at runtime, so a standalone build or pruned Docker image must still contain it. Check that the import is from a Server Component or Route Handler, not a Client Component, which this option does not affect.
Do I need to list sharp or Prisma in serverExternalPackages?
No. Next.js ships a list of popular packages that are opted out automatically, including sharp, @prisma/client, better-sqlite3, mongodb, pino, and playwright. Only add packages that are not already on that list.
More examples
A native addon plus a standalone output
@acme/image-codec ships a prebuilt .node binary that a bundler cannot inline. Externalizing it makes the server require it at runtime — which means the package has to be present in the standalone output. If the container starts and throws MODULE_NOT_FOUND for it, file tracing did not copy it and you need to add it to the image yourself.
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
output: 'standalone',
serverExternalPackages: ['@acme/image-codec'],
}
export default nextConfigThe conflict that fails the build
The two options are opposites: one says compile and bundle this package, the other says do not touch it. Next.js rejects the config instead of silently picking one. If a package needs compiling for the client but must stay external on the server, split it into two entry points or two packages.
import type { NextConfig } from 'next'
// This configuration fails at the start of next build
const nextConfig: NextConfig = {
transpilePackages: ['@acme/ui'],
serverExternalPackages: ['@acme/ui'],
}
export default nextConfigChecking whether a package is already excluded
Only the package that is actually failing needs an entry. Adding already-defaulted packages makes the config look like it is doing work it is not, and hides which dependency was the real problem.
import type { NextConfig } from 'next'
// sharp, @prisma/client, pino, better-sqlite3, mongodb, playwright and
// dozens of others are opted out by default — listing them again is a no-op.
const nextConfig: NextConfig = {
serverExternalPackages: ['@acme/pdf-renderer'],
}
export default nextConfig
Discussion