Today we are thrilled to introduce ncc, a simple Node.js CLI program and API for compiling Node.js projects into a single JavaScript file.
Inspired by native compiler toolchains, such as go, that export a static ELF binary file, ncc will output a self-contained script that bundles all its dependencies by leveraging webpack.

A walkthrough

To install it, run
npm i -g @zeit/ncc
It will download the ncc compiler, which has been compiled with ncc itself.
Let's create a project and add a dependency:
cd myapp
npm i chalk
And populate your main file index.js:
const chalk = require("chalk");
console.log("Hello world!"));
Then we can ncc run it:
Or we can ncc build it for production:
ncc implements a go-style API and design philosophy. Compiling a program should be intuitive, single-command, zero-configuration.
For more usage information, run ncc help or check out the api docs.


Serverless deployment

We wrote ncc by extracting the best practices out of our @now/node builders.
Consider this example of deploying apollo as a Now 2.0 lambda (
The entire bundle of code actually used by our entrypoint amounts to 950kb, which considers apollo-server-express, express, graphql and all their sub-dependencies.
In contrast, node_modules alone amounts to 35 times the size of our bundle:
Thus, ncc makes deployment faster and more secure, by only shipping the necessary code to production.

Faster distribution

In the early days of ncc development, it used to bundle webpack as a regular npm dependency. It eventually became good enough to self-host.
We can now compare the installation duration of the non-ncc version:
In stark contrast to installing the ncc version (usually 5-10x faster):

Faster bootup

To demonstrate this, we simply time how long it takes to require("ncc") (which requires webpack, a very large amount of JavaScript).
This is how long it takes to require src/index.js, where every subsequent require invokes file-system lookups.
When run through ncc and minify we consistently see a 50% improvement in boot-up performance, which will only get faster.

Future work

These represent active areas of work following our initial release. Contributions are welcome.


Issue: #46
Generally speaking, ncc is already quite fast, even though no optimizations have been made.
By leveraging a global cache, we intend for re-runs and re-builds to get incrementally faster with no tradeoffs in safety.

Built-in Minification

Issue: #62
Minification is a remarkably safe operation that has significant boot-up time and package size benefits.
It will be default off for ncc run and default on for ncc build. Developers might want to opt out of this feature when debugging programs or dependencies.
Furthermore, ncc will favor safety over maximally optimal minification.


Issue: #63
Stack traces that are produced by ncc run should be accurate by default. Developers should be able to opt-into emitting source maps for ncc build production outputs.

Automatic Dependency Installation

Issue: #56
Following go's example, we intend for ncc to transparently ensure dependencies have been installed, by executing yarn install or npm install automatically.
This will help develop more confidently. For example, the following is error-prone:
git pull
node my-program
This is because after git pull the dependencies (package.json, yarn.lock, package-lock.json) might have changed.
However, the following will always be predictable and safe:
git pull
ncc run my-program
We also look forward to evaluating ncc cooperating with next-generation installation approaches like tink and yarn pnp.

TypeScript Support

Issue: #31
TypeScript is now being used by up to 50% of Node.js developers according to recent surveys.
It addresses important gaps in the Node.js ecosystem (such as static typing and JSX support). Crucially, we can add it unobtrusively by introducing support for the .ts[x] extensions:
ncc build my-app.ts

V8 Compiler Cache

Issue: #51
In addition to minification, it's possible to get further boot-up benefits by leveraging the V8 API that emits an image of the parse and compile step.
Modules like v8-compile-cache have successfully made programs like yarn (which is distributed as a single-file, in the same spirit as ncc) up two 2x faster.

Native addons support

Issue: #57
The contract of ncc is that it yields an output directory containing one or more files. Typically it's one, but we also perform static analysis on synchronous filesystem reads.
For example, pdkfit and its dependencies read a lot of files that are bundled with their packages upon initialization:
We plan to use the same technique to support .node files, making ncc a complete solution that supports the vast majority of npm modules in the ecosystem out of the box.

Frequently asked questions

Why `ncc run file.js` instead of `node file.js`

Using ncc run is optional, but it has the following current and future benefits:
  • Fewer surprises upon ncc build. While ncc gets remarkably close to the native node semantics (with many integration tests) from time to time some modules with unusually-dynamic dependencies or filesystem reads could give it trouble.
  • TypeScript support (planned)
  • Transparent dependency installation (planned)

How is this different from webpack, rollup, parcel?

We wanted to focus on a development experience that maximizes productivity, followed the semantics of the Node.js platform out of the box and mirrored the conventions of other well-designed and battle-tested languages.
This means that it should do the right thing out of the box, with no extra configuration.

How is this different from `pkg`?

pkg is complimentary to ncc, by taking any JavaScript source(s) and bundling them into an executable that bundles the Node.js runtime inside. While ncc outputs scripts (text), pkg outputs executables (binary).
In some cases you will want to use them together, and in others, independently.