
Product
Socket for Jira Is Now Available
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.
rollup-plugin-node-externals
Advanced tools
Automatically declare NodeJS built-in modules and npm dependencies as 'external' in Rollup/Vite config
A Rollup/Vite plugin that automatically declares NodeJS built-in modules and npm dependencies as external.
By default, Rollup doesn't know a thing about NodeJS, so trying to bundle simple things like import path from 'node:path' in your code results in an Unresolved dependencies warning.
The solution here is quite simple: you must tell Rollup that the node:path module is in fact external. This way, Rollup won't try to bundle it in and rather leave the import statement as is (or translate it to a require() call if bundling for CommonJS).
However, this must be done for each and every NodeJS built-in you happen to use in your program: node:path, node:os, node:fs, node:url, etc., which can quickly become cumbersome when done manually.
So the primary goal of this plugin is simply to automatically declare all NodeJS built-in modules as external. As an added bonus, this plugin will also declare your dependencies (as per your local or monorepo package.json file(s)) as external.
Use your favorite package manager. Mine is npm:
npm install --save-dev rollup-plugin-node-externals
The plugin is available both as the default export and as a named export:
import nodeExternals from 'rollup-plugin-node-externals'
and
import { nodeExternals } from 'rollup-plugin-node-externals'
will both work.
You generally want to have your runtime dependencies (those that will be imported/required at runtime) listed under dependencies in package.json, and your development dependencies (those that should be bundled in by Rollup/Vite) listed under devDependencies.
If you follow this simple rule, then the default settings are just what you need:
// rollup.config.js / vite.config.js
export default {
...
plugins: [
nodeExternals(),
]
}
This will bundle your devDependencies in while leaving your dependencies, peerDependencies and optionalDependencies external.
Should the defaults not suit your case, here is the full list of options.
import nodeExternals from 'rollup-plugin-node-externals'
export default {
...
plugins: [
nodeExternals({
// Mark NodeJS builtins external. Default: true.
builtins?: boolean
// node: prefix handing for importing NodeJS builtins. Default: 'add'.
builtinsPrefix?: boolean | 'add' | 'strip' | 'ignore'
// The path(s) to your package.json. Default: read below.
packagePath?: string | string[]
// Mark dependencies external? Default: true.
deps?: boolean
// Mark devDependencies external? Default: false.
devDeps?: boolean
// Mark peerDependencies external? Default: true.
peerDeps?: boolean
// Mark optionalDependencies external? Default: true.
optDeps?: boolean
// Modules to force include in externals. Default: [].
include?: string | RegExp | (string | RegExp)[]
// Modules to force exclude from externals. Default: [].
exclude?: string | RegExp | (string | RegExp)[]
})
]
}
Set the builtins option to false if you'd like to use some shims/polyfills for those. You'll most certainly need an other plugin as well.
How to handle the node: scheme when importing builtins (i.e., import path from 'node:path').
add or true (the default, recommended), the node: scheme is always added if missing, so path becomes node:path. In effect, this dedupes your imports of Node builtins by homogenizing their names to their schemed version.strip or false, the scheme is always removed, so node:path becomes path. In effect, this dedupes your imports of Node builtins by homogenizing their names to their scheme-less version. Schemed-only builtins like node:test or node:sqlite are never stripped.ignore will simply leave all builtins imports as written in your code. Caveat: if you write node:path but one of your bundled dependencies uses path (or the other way around), your bundle will end up with both node:path and path imports.[!NOTE] Scheme handling is always applied, regardless of the
builtinsoptions being enabled or not.
This option allows you to specify which package.json file(s) should be scanned for dependencies.
If not specified, the default is to start with the current directory's package.json then go up scan for all package.json files in parent directories recursively until either the root git directory is reached, the root of the monorepo is reached, or no other package.json can be found.
Set the deps, devDeps, peerDeps and optDeps options to false to prevent the corresponding dependencies from being externalized, therefore letting Rollup/Vite bundle them with your code.
Use the include option to force include certain dependencies into the list of externals regardless of other settings:
nodeExternals({
deps: false, // Deps will be bundled in
include: 'some-dep' // Except for 'some-dep'
})
Conversely, use the exclude option to remove certain dependencies from the list of externals regardless of other settings:
nodeExternals({
deps: true, // Keep deps external
exclude: /^this-dep/ // Yet we want `this-dep` (and all its sub-paths) bundled in
})
include and exclude are silently ignored. This allows for conditional constructs like exclude: process.env.NODE_ENV === 'production' && 'my-prod-only-dep'.include: /^lodash/ will externalize lodash and also lodash/map, lodash/merge, etc.It uses an exact match against your imports as written in your code. No resolving of path aliases or substitutions is made.
If you're also using @rollup/plugin-node-resolve, make sure this plugin comes before it in the plugins array:
import nodeExternals from 'rollup-plugin-node-externals'
import nodeResolve from '@rollup/plugin-node-resolve'
export default {
...
plugins: [
nodeExternals(),
nodeResolve(),
]
}
Note that as of version 7.1, this plugin has a enforce: 'pre' property that will make Rollup and Vite call it very early in the module resolution process. Nevertheless, it is best to always make this plugin the first one in the plugins array.
Rollup's own external configuration option always takes precedence over this plugin. This is intentional.
This plugin has been compatible with Vite out-of-the-box since version 7.1. If you found an old tutorial on the Internet telling you to use some special trick to make it work with Vite… just don't. Here's how you should write your vite.config.js:
import { defineConfig } from 'vite'
import nodeExternals from 'rollup-plugin-node-externals'
export default defineConfig({
...
plugins: [
nodeExternals()
// other plugins follow
]
})
[!IMPORTANT] Make sure you use the top-level plugins array in
vite.config.jsas shown above. Usingbuild.rollupOptions.pluginswill probably not work. See #35 for details.
This version mainly enhances performance when used in watch mode. This was achieved by ensuring that the buildStart hook builds the full dependencies list only when necessary.
See Github releases for full change log.
MIT
The rollup-plugin-peer-deps-external package is similar in that it also helps manage external dependencies. It specifically focuses on excluding peer dependencies from the bundle, which is useful for library authors who want to ensure that peer dependencies are not bundled. Unlike rollup-plugin-node-externals, it does not automatically exclude built-in Node.js modules.
rollup-plugin-auto-external is another package that automatically marks dependencies as external based on the package.json file. It is similar to rollup-plugin-node-externals in that it helps manage external dependencies, but it does not specifically target Node.js built-in modules. It is more focused on automating the process of marking dependencies as external based on the package's dependencies and peerDependencies fields.
FAQs
Automatically declare NodeJS built-in modules and npm dependencies as 'external' in Rollup/Vite config
The npm package rollup-plugin-node-externals receives a total of 264,575 weekly downloads. As such, rollup-plugin-node-externals popularity was classified as popular.
We found that rollup-plugin-node-externals demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.