Open-source project
parcel-bundler/parcel avatar
parcel-bundler/parcel

parcel: zero config, a Rust compiler, and a self-hosted npm registry

The zero configuration build tool for the web. 📦🚀

44,022 stars2,289 forksJavaScriptMIT

At a glance

What is it?
parcel-bundler/parcel is a web build tool whose JavaScript compiler is written in Rust, whose development branch is named v2, and whose newest tag is eight months older than its last commit. The README contains no install command at all, and building the project means bootstrapping Parcel with Parcel.
Who is it for?
parcel fits a team that wants a build tool to work before it is configured, and that will accept Rust in its build path and a Yarn and Lerna monorepo if they contribute upstream. It does not fit someone who needs a config example, a flag reference or a pinned release in the README, because none of those exist there.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The development branch is named v2 and the newest tag stopped in February

The default branch of this repository is called v2, not main or master. That single naming choice removes the usual staging area: there is no separate development line that will become the next major, because the line you follow to get the newest work is the line named after the current major version.

The tags are where the pause is. v2.16.1 was published on 2025-11-05, v2.16.2 on 2025-12-06 and v2.16.4 on 2026-02-02, and the last push to the v2 branch was on 2026-09-29. The repository is not archived, so nothing has stopped moving, but the newest published release is roughly eight months behind the branch.

That gap is the thing to plan around. If you install from npm you get v2.16.4, and any bug fixed on the branch after February is something you are missing without a way to see it, because the README carries no changelog pointer and the CHANGELOG.md at the root is the only place the differences would be written down. There is a documentation page for migrating from Parcel v1, which tells you the project invests in upgrade paths, and no equivalent for moving from a February tag to the branch.

Parcel builds its own CLI and dev server with a checked-in Parcel

Look at the build script and the bootstrap problem appears. The build target runs yarn build-bundles and then a gulp step, and build-bundles does not compile from nothing: it sets PARCEL_SELF_BUILD=true and invokes a Parcel binary that already exists in node_modules to build the packages the rest of the toolchain needs.

The package list it builds is small and specific, which tells you where the bootstrap boundary sits: packages/core/{fs,codeframe,package-manager,utils}, packages/reporters/{cli,dev-server}, and packages/utils/{parcel-lsp,parcel-lsp-protocol,parcel-watcher-watchman-js,error-overlay}. The command uses the glob packages/*/*/lib for the rimraf step, and it passes --no-cache so a stale cache cannot mask a broken source tree.

The consequence is the classic one for a self-hosting build tool. If the checked-in bootstrap binary is missing, or too old for the source you are trying to build, you cannot fix it from this repository alone, because the thing that would fix it is the thing that is broken. The README does not document the bootstrap order or how to seed node_modules for a fresh clone, and the fix is to install a released parcel first.

Three crates.io HTML parsers are replaced by a fork on one branch

The Rust side has its own workspace, and it patches crates.io rather than depending on it. Cargo.toml declares a workspace with resolver 2, whose members are the crates under crates/ and one package inside the JavaScript tree, then replaces the whole html5ever family:

toml
[patch.crates-io]
html5ever = { git = "https://github.com/devongovett/html5ever.git", branch = "xmlns-attrs" }
xml5ever = { git = "https://github.com/devongovett/html5ever.git", branch = "xmlns-attrs" }
markup5ever = { git = "https://github.com/devongovett/html5ever.git", branch = "xmlns-attrs" }

html5ever, xml5ever and markup5ever are the HTML and XML parsing stack, and all three now resolve from a fork under one maintainer's account on a branch named for a feature. A force-push to that branch, or its deletion, breaks the build, and there is no crates.io version to fall back to because the patch section overrides what the registry would serve.

The profiles in the same file are worth reading too. A canary profile inherits release and adds debug information, so canary binaries ship with symbols and are meant to be debugged, while the release profile strips symbols. The canary build has its own script, build-native-canary, alongside build-native-release and a wasm variant, which is a lot of artifact shapes for one compiler.

The root package is private, the workspace glob is two levels deep, and verdaccio tests publishing

The root manifest is not the package you install. It is named @parcel/monorepo, it is marked private, and the published artefact is the parcel package on npm instead. What the root holds is the workspace definition:

json
"name": "@parcel/monorepo",
"private": true,
"workspaces": [
  "packages/*/*"
]

The glob is two levels deep, packages/*/*, which matches packages/core/fs and packages/reporters/cli but not a package placed directly under packages/. Adding a package in the wrong place does not fail loudly, it is simply not part of the workspace, and lerna is configured alongside it in lerna.json to handle the per-package scripts.

The publishing story is the unusual part. verdaccio.yml and verdaccioPublish.js at the root are a self-hosted npm registry, which means releases are rehearsed against a local registry before anything is pushed to npm. For a project with this many packages that is the difference between a bad publish and an incident, and it is the kind of infrastructure that only shows up in a monorepo that has been bitten.

Yarn, Lerna, gulp, Cargo, Flow, ESLint and a nightly formatter in one tree

Count the toolchains in the root and the contributor cost is clear. JavaScript is managed by Yarn with a checked-in .yarn/ directory, .yarnrc.yml and yarn.lock, and orchestrated by lerna.json. Rust is pinned by rust-toolchain and formatted with rustfmt.toml. Types are checked with Flow, which is why .flowconfig, flow-libs/ and flow-typed/ are all at the root. Linting and formatting for JavaScript is eslint with .eslintrc.json and .eslintignore, prettier with .prettierrc and .prettierignore, and husky in .husky/ for commit hooks. Tests run under mocha, configured in .mocharc.json, and there is a .devcontainer/ for a containerised editor.

The scripts show the split. The format target writes JavaScript with prettier and then runs cargo +nightly fmt --all, so formatting Rust needs a nightly toolchain even though rust-toolchain pins the build toolchain. The check target is flow check, and the lint target is eslint, then prettier in list-different mode, then cargo fmt.

There is also a patches/ directory, a .proxyrc.js for the dev server, and a gulpfile.js that the production build step drives. Nobody gets all of that on day one, and a contributor who installs the JavaScript side and runs the build will find out which parts they missed when a script fails on a missing binary.

The Cargo workspace reaches into the JavaScript tree, so a transformer lives in both

The Rust workspace is not confined to crates/:

toml
[workspace]
resolver = "2"
members = [
  "crates/*",
  "packages/transformers/js/core"
]

The JavaScript transformer's core is a Cargo member that lives inside the JavaScript package layout. That is the mechanism behind the README claim that the JavaScript compiler is written in Rust, and it has a consequence for anyone touching it: a change to that transformer is a change in a directory under packages/ that is also a Rust crate, and it is picked up by the crates/* glob only for crates, not for packages.

So there are two discovery rules in one repository. A new crate under crates/ is a workspace member the moment it exists, with no manifest edit. A new package under packages/ has to satisfy the two-level glob and be a Yarn workspace at the same time. Neither rule is written down in the README, and both are learned by making the mistake once.

The README has no install command, no config sample and no flag reference

Read the README as an evaluation document and it is thin. It describes five qualities, links three getting-started guides, points at the documentation site, names Discord, GitHub Discussions and Twitter as the support channels, and closes with Open Collective backer and sponsor sections. There is no install line, no package.json sample, no CLI flag and no configuration example anywhere in it.

Everything operational is on the website, split across three entry points: building a webapp, building a library, and migrating from Parcel v1. The flag reference and the configuration format live under parceljs.org/docs. A team deciding whether to adopt Parcel therefore has to read the documentation site to answer a question the README leaves open, which is fine as a division of labour and awkward as a single-page review.

What the README does commit to is behaviour rather than syntax. It says Parcel supports many languages and file types out of the box, from HTML, CSS and JavaScript to images, fonts and videos, with a built-in dev server, hot reloading and error diagnostics. It says everything is cached so the same code is never built twice, which it compares to watch mode surviving a restart. And it says production optimisation is automatic: tree-shaking and minifying of JavaScript, CSS and HTML, image resizing, content hashing and automatic code splitting. Those are the claims to test first, because they are the ones that decide whether the zero-configuration promise holds for your project.

Editorial conclusion

parcel fits a team that wants a build tool to work before it is configured, and that will accept Rust in its build path and a Yarn and Lerna monorepo if they contribute upstream. It does not fit someone who needs a config example, a flag reference or a pinned release in the README, because none of those exist there. Verify first which version you are getting, since the v2 branch's newest tag is v2.16.4 from 2026-02-02 while the last commit was on 2026-09-29, and check that a source build can bootstrap at all before planning to fork it.

Frequently asked questions

How do I install Parcel?

The README has no install command and points to three getting-started guides instead: building a webapp, building a library, and migrating from Parcel v1, all on parceljs.org. The published package is on npm as parcel, and the root repository package is @parcel/monorepo, which is marked private and is not what you install.

What file types does Parcel handle without configuration?

Web technologies including HTML, CSS and JavaScript, plus assets such as images, fonts and videos, along with zero-config JSX and TypeScript compilation. It also includes a dev server with hot reloading and error diagnostics, and transforms output for target environments from modern to legacy browsers.

What does Parcel do when building for production?

The README says it optimizes the whole application automatically: tree-shaking and minifying of JavaScript, CSS and HTML, resizing and optimizing images, content hashing, and automatic code splitting. It builds in parallel using worker threads and caches everything so the same code is not built twice.

How do I build Parcel from source?

The root package @parcel/monorepo uses Yarn workspaces over packages/*/*, and the build script runs build-bundles, which sets PARCEL_SELF_BUILD=true to build the core and reporter packages with a Parcel binary already present in node_modules. Native binaries come from node scripts/build-native.js, with separate release, canary and wasm variants.

What is the latest Parcel release?

The most recent tag is v2.16.4, published on 2026-02-02, after v2.16.2 on 2025-12-06 and v2.16.1 on 2025-11-05. The default branch is named v2 and its last push was on 2026-09-29, so the newest published release is about eight months behind the branch, and the repository is not archived.

Official sources

  1. License: MIT
  2. parcel-bundler/parcel on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/parcel-bundler-parcel.svg)](https://hysenlabs.com/projects/parcel-bundler-parcel)