Other features
Assorted things netpack does today that don’t warrant their own page yet.
Output formats
By default netpack emits ES modules; --format (esm, cjs, umd, systemjs)
picks the envelope each JavaScript bundle is wrapped in. See
Output formats for the details, limitations, and why ESM
is the best choice.
Tree shaking
netpack computes which exports of each module are actually used across the
whole graph (once per build, cached) and drops the rest — an export no
importer ever references doesn’t make it into the output bundle.
Source maps
npx netpack bundle src/index.html --sourcemap
Emits a .js.map next to each JavaScript bundle. serve always emits
source maps, regardless of this flag, since you’re debugging live.
Minification
npx netpack bundle src/index.html --minify
Optimizes JS, CSS and the HTML shell for size. bundle’s summary table
shows the effect directly — compare a build with and without --minify.
Log level (--log-level)
Controls how much netpack prints. It is a global flag — it works with any
command (bundle, serve, analyze, …):
npx netpack bundle src/index.html --log-level warning
The levels, least to most verbose, are silent, error, warning, info
(default), debug, and verbose. Each shows its own tier and everything below
it — warning shows warnings and errors but not the normal build chatter,
silent shows nothing, and debug/verbose add extra diagnostic detail on top
of the usual output.
Compile-time constants (--define)
Replaces a global identifier or member expression with a constant expression before parsing — the value is inlined, so dead branches tree-shake away.
npx netpack bundle src/index.html --define __VERSION__=\"1.4.0\" --define DEBUG=false
The replacement text must be valid JavaScript, so a string constant keeps its
quotes (--define API=\"/v2\"). process.env.NODE_ENV is defined for you
(development under serve, production for an optimized build); a --define
of your own overrides it. Both bundle and serve accept the flag, repeatably.
Import aliases (--alias)
Rewrites an import specifier to another package or a local file.
npx netpack bundle src/index.html --alias react=preact/compat --alias @=./src
A bare target (preact/compat) is resolved like any dependency; a path target
(./src) is resolved from the working directory. Matching is on the specifier,
so import "@" picks up the alias.
TypeScript paths
netpack also honours the compilerOptions.paths mapping from the tsconfig.json
closest to the importing file as a resolution fallback, so aliases like
@/* → ./src/* work without a matching --alias. Because the lookup is
per-file, a monorepo where each package has its own tsconfig.json (and its own
paths) resolves correctly:
// tsconfig.json
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] } } }
With that, import { Foo } from "@/components" resolves to src/components.
Targets are resolved relative to baseUrl (or the tsconfig’s own directory when
baseUrl is absent). Each tsconfig.json is parsed at most once and the
directory lookup is cached, and the mapping is only consulted when a specifier
doesn’t resolve normally, so it adds no cost to regular imports. An explicit
--alias still wins.
Loaders (--loader)
Overrides how a file extension is turned into a module, replacing the built-in handling.
npx netpack bundle src/index.html --loader .svg=text --loader .frag=text
Available loaders: js, jsx, ts, tsx, json, css, text (import the
file’s contents as a string), base64, dataurl (inline as a data: URI),
file/copy (emit the file and import its URL), and empty. The
inline loaders (text/base64/dataurl/empty) produce a JS module, so they
apply to files imported from JavaScript.
Cache-busting file names (--entry-names)
Adds a content hash to emitted bundle names so they can be served with a long-lived cache. References from the HTML entry (and between bundles) are rewritten to the hashed names automatically.
npx netpack bundle src/index.html --entry-names [name]-[hash]
The template understands [name] and [hash]; the default is [name] (no
hash). The entry HTML document keeps its own name so it stays linkable.
Imported assets are content-hashed already, independently of this flag. The hash
reflects each bundle’s own contents, so a change confined to a shared bundle
re-hashes that bundle but not the entries that import it.
Public path (--public-path)
Prepends a base path or URL to every reference to an emitted file — bundle
chunks, assets, and the script/link/img targets in the HTML shell — so the
output can be served from a CDN or a sub-path instead of next to the document.
npx netpack bundle src/index.html --public-path https://cdn.example.com/app
With no public path (the default) references stay document-relative
(./app.js); with one they become https://cdn.example.com/app/app.js. It
applies across every output format.
Banner (--banner)
Places arbitrary text on the very first line of the entry JS bundle, followed by a newline — typically a license/copyright header or a runtime pragma.
npx netpack bundle src/index.html --banner "// (c) 2026 Acme, Inc. — MIT"
The banner is emitted verbatim, so it is your responsibility to make it valid for
the position it lands in (a // or /* … */ comment, a "use client"-style
directive, a shebang, …). It goes on top of every entry JS bundle; shared split
chunks are left untouched. An empty banner (the default) emits nothing. Source
maps stay accurate: mappings are shifted to account for the added lines. Both
bundle and serve accept the flag.
Licenses (--licenses)
By default netpack collects the legal comments in your dependencies — the
/*! … */, //! …, @license, @preserve and @copyright blocks bundlers are
expected to preserve — and keeps the relevant ones in each bundle’s head (after
any --banner). --licenses picks how that’s handled:
| Value | Behaviour |
|---|---|
skip (default) | Don’t collect or emit any licenses. |
preamble | Keep each module’s legal comments at the top of the bundle it lands in, after the banner. |
json | Write a licenses.json manifest (package name, version, license id, license text) to the output directory. |
spdx | Write a licenses.spdx manifest in the SPDX tag-value format. |
npx netpack bundle src/index.html --licenses spdx
The json/spdx manifests list one entry per resolved dependency (deduplicated by
name+version). If a file with that name already exists in the output (for example
one copied from public/), a short suffix is added — licenses-1a2b3c.json — so
nothing is clobbered. The declared license comes from each package’s
package.json license field; the license text, when present, from its LICENSE
file.
Exports conditions (--conditions)
Adds custom exports conditions on top
of the platform defaults, widening which conditional branches of a dependency’s
package.json exports map are eligible.
npx netpack bundle src/index.html --conditions development --conditions browser
User conditions take priority over the platform’s built-ins; default always
matches last.
Externalizing packages (--packages)
--packages external keeps every bare (i.e. node_modules) import external
instead of bundling it — the standard way to build a library, or a Node app whose
dependencies are installed separately. Relative and absolute imports are still
bundled.
npx netpack bundle src/lib.ts --packages external --format esm
This is the bulk equivalent of listing every dependency with --external.
Watch mode & HMR
netpack serve watches the filesystem and recompiles on every change with
no extra configuration — see
Getting started
for how updates reach the browser (granular hot-swap vs. full reload), and
React & JSX for
how React component state survives an edit when react-refresh is
installed.
For a build without a server, netpack bundle --watch rebuilds and rewrites the
output directory whenever a source file that took part in the build changes:
npx netpack bundle src/index.html --outdir dist --watch
It writes to disk (no dev server, no HMR) and runs until interrupted — handy when
another process serves dist/.
Bundle analyzer
Covered in full in Bundle analyzer — the interactive graph explorer, the dependency vulnerability audit, and the optimization recommendations that flag where your chunks could be split more efficiently.
Build-time code generation
Covered in full in Build-time code generation — a .codegen
file is executed as a small Node module at build time, and whatever it
returns becomes that module’s JavaScript source.
Import maps, externals & shared dependencies
Covered in full in Import maps & externals.
Module Federation
Covered in full in Module Federation.
Native, npm-installable binary
netpack ships as a single Ahead-of-Time-compiled binary per platform
(@netpack/linux-x64, @netpack/osx-arm64, @netpack/win-x64), installed
through the netpack npm wrapper like any other JS build tool — no JIT
warmup, no separate runtime to install. This is also why the Node
dependency called out above (Sass/LESS/PostCSS/codegen) is opt-in rather
than a baseline requirement: it only spins up when you actually import
something that needs it.