|$ curl https://forge-ai.dev/api/markdown?path=docs/build-tools/parcel
$cat docs/parcel-bundler.md
updated Recently·25 min read·published

Parcel Bundler

Build ToolsBeginner to Intermediate🎯Free Tools
Introduction

Parcel is a zero-configuration web bundler that requires no setup. It automatically detects and configures transforms, bundling, dev server, and production optimizations based on your project files. Parcel v2 is written in Rust for native performance.

Getting Started
getting-started.sh
Bash
1# Install Parcel
2npm install --save-dev parcel
3
4# Add scripts to package.json
5# "scripts": {
6# "dev": "parcel src/index.html",
7# "build": "parcel build src/index.html",
8# "preview": "parcel dist/index.html"
9# }
10
11# Start dev server (zero config!)
12npm run dev
13
14# Production build
15npm run build
16
17# Parcel auto-detects:
18# - TypeScript (transpiles)
19# - JSX/TSX (transpiles)
20# - CSS/SCSS/Less (processes)
21# - Images (optimizes, generates hashes)
22# - JSON imports (parses)
23# - HTML (processes references)
Targets

Targets tell Parcel where to output bundles and what browsers/environments to support. Parcel v2 uses browserslist for browser targeting.

package.json
JSON
1// package.json — configure targets
2{
3 "targets": {
4 "main": {
5 "context": "browser",
6 "outputFormat": "global",
7 "distDir": "dist"
8 },
9 "module": {
10 "context": "browser",
11 "outputFormat": "esmodule",
12 "distDir": "dist/esm",
13 "isLibrary": true,
14 "sourceMap": true
15 },
16 "node": {
17 "context": "node",
18 "outputFormat": "commonjs",
19 "distDir": "dist/node",
20 "isLibrary": true,
21 "engines": { "node": ">=18" }
22 }
23 },
24 "browserslist": ">= 0.5%, last 2 versions, not dead"
25}
Code Splitting
code-splitting.ts
TypeScript
1// Parcel automatically code-splits on dynamic imports
2// No configuration needed!
3
4// Route-based splitting
5const Dashboard = React.lazy(() => import("./pages/Dashboard"));
6const Settings = React.lazy(() => import("./pages/Settings"));
7
8// Conditional imports
9async function loadPlugin(name: string) {
10 const plugin = await import(`./plugins/${name}`);
11 return plugin.default;
12}
13
14// CSS splitting — each component's CSS is a separate chunk
15import "./Button.css"; // Automatically split per import
16
17// Shared chunks — Parcel deduplicates shared modules
18// between routes automatically
19
20// Named exports with dynamic import
21const { formatDate, parseDate } = await import("./date-utils");
22// Only the used exports are bundled (tree-shaking)
Monorepo Support
monorepo-package.json
JSON
1// package.json — workspace configuration
2{
3 "workspaces": ["packages/*"],
4 "targets": {
5 "default": {
6 "distDir": "dist"
7 }
8 }
9}
10
11// Parcel resolves imports across workspaces
12// If package-a imports from package-b, Parcel
13// uses the source directly (no build step needed)
14// This enables instant HMR across packages

info

Parcel's workspace support means you can develop across packages with instant HMR. No need to build packages before importing them — Parcel resolves source files directly during development.
Dev Server & HMR

Parcel starts a development server from an HTML entry with Hot Module Replacement enabled by default. CSS updates typically apply without a full reload; JS HMR depends on the module accepting updates (framework integrations improve this).

dev.sh
Bash
1# Serve with HMR
2npx parcel src/index.html --port 1234 --open
3
4# Disable HMR when debugging full reloads
5npx parcel src/index.html --no-hmr
6
7# HTTPS locally (useful for secure-context APIs)
8npx parcel src/index.html --https

info

Prefer an HTML entry for web apps — Parcel follows script/link tags, discovers the graph, and wires HMR without a separate webpack-dev-server config.
Automatic Transforms

Parcel v2 uses a transformer pipeline (often Rust-backed) to compile TypeScript, JSX, CSS modules, Sass, images, and more based on file extensions and package.json metadata.

Asset typeDefault behaviorConfigure via
.ts / .tsxTranspile (not full typecheck)tsconfig + engines/browserslist
.css / .scssBundle, minify in prodPostCSS config if present
CSS modules*.module.css scopedNaming conventions
ImagesHash + optimizequery params / image pipelines
.jsonImportable modules

warning

Parcel does not replace tsc --noEmit. Keep a typecheck script in CI — transforms can succeed on type-incorrect code.
.parcelrc & Plugins

When zero-config is not enough, extend the pipeline with .parcelrc. Extend the default config instead of replacing it wholesale.

.parcelrc
JSON
1{
2 "extends": ["@parcel/config-default"],
3 "transformers": {
4 "*.{gl,glsl}": ["...", "@parcel/transformer-glsl"]
5 },
6 "optimizers": {
7 "*.js": ["...", "@parcel/optimizer-swc"]
8 }
9}
📝

note

The "..." sentinel keeps default transformers/optimizers and inserts yours in the chain — omitting it can drop critical built-ins.
Environment Variables & Modes

Parcel inlines process.env.NODE_ENV and supports .env files. Only expose values intended for the browser — treat client bundles as public.

env.sh
Bash
1# .env — local defaults
2# .env.production — production build overrides
3
4# Access in code (bundler replaces at build time)
5# process.env.API_URL
6
7# Production build
8NODE_ENV=production npx parcel build src/index.html

danger

Do not put database credentials or private API keys in .env files that Parcel inlines into browser code. Keep secrets on the server.
Production Builds
ConcernParcel behaviorPractice
MinificationEnabled in parcel buildKeep source maps for error tracking
Content hashingHashed filenames by defaultCache-Control long-lived on hashed assets
Scope hoistingESM concatenation for sizePrefer ESM dependencies
Differential bundlingModern + legacy when neededSet realistic browserslist
prod.sh
Bash
1npx parcel build src/index.html \
2 --dist-dir dist \
3 --no-source-maps # only if you upload maps another way — usually keep maps
4
5# Inspect output
6ls -lh dist
Parcel vs Vite
AspectParcelVite
Config philosophyZero-config HTML entryConfig + rich plugins
Dev architectureBundled dev graphNative ESM + esbuild deps
EcosystemSmaller plugin setLarge framework templates
Best whenHTML-first apps, low configSPA frameworks, plugin needs

best practice

Choose Parcel when the team wants minimal tooling ceremony and an HTML entry. Choose Vite when you need framework scaffolding, SSR plugins, or a specific Vite plugin.
When to Use Parcel
  • Marketing sites and multi-page HTML apps with light JS.
  • Prototypes where writing webpack/vite config is pure overhead.
  • Monorepos that benefit from source resolution across packages.
  • Avoid as the sole tool for Module Federation-heavy micro-frontends — prefer Webpack/Rspack.
$Blueprint — Engineering Documentation·Section ID: BT-PC-01·Revision: 1.0

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.