Parcel 20 ๐ฆ The .parcelrc File โ Optional configuration & extending defaults
The .parcelrc file is Parcel’s plugin configuration system, and it is optional in the sense that Parcel ships with a default config that works for most projects. But the moment you need a custom transformer, a different resolver, or a named pipeline, .parcelrc is the mechanism that makes it possible. The file is written in JSON5, which supports comments, unquoted keys, and trailing commasโa detail that matters when you are debugging a configuration and want to leave a note explaining why a glob exists . The design philosophy is different from other bundlers: Parcel does not ask you to configure the entire build pipeline from scratch. It asks you to extend the default pipeline, inserting your plugins at the right points without losing the defaults.
The "..." syntax is the center of this design. When you write "*.svg": ["...", "@parcel/transformer-svg-jsx"], the "..." tells Parcel to run its default SVG transformer first, then run your plugin on the result . Without the "...", your plugin replaces the default entirely, and the default transformationsโthe ones that make Parcel workโnever run. This is the single most important concept in .parcelrc: you are almost always extending, not replacing.
Key point: The "..." syntax embeds the next-priority pipeline into your custom pipeline. Omitting it replaces the default pipeline instead of extending it. For most plugin configurations, the correct form is ["...", "your-plugin"] or ["your-plugin", "..."], not ["your-plugin"] alone.
Why the .parcelrc format is structured this way
The glob map priority problem. Many fields in .parcelrcโtransformers, packagers, optimizersโare objects that map glob patterns to plugin arrays. The order of the keys in the object defines their priority. When Parcel processes a file, it checks the globs in the order they appear in the config, and the first match wins. If no glob in the current config matches, Parcel falls back to the globs in the extended config . This is why a config with "icons/*.svg" before "*.svg" applies the icon-specific transformer to files in the icons/ directory and the general transformer to everything else. The order is not alphabetical or based on specificity; it is purely positional, and it is the developer’s responsibility to order the globs correctly.
The extension chain problem. The extends field points to another config, usually @parcel/config-default. The chain can be multiple levels deep: a project config extends a framework config, which extends the default config. The resolution is depth-first, and the first match in the chain wins. A plugin that is inserted with "..." at a given position inherits the fallback behavior of the extended config at that position. A plugin that is inserted without "..." has no fallback, and files that do not match its glob are not processed by the default pipeline . The chain is the reason a custom config does not need to re-declare every default plugin; it only needs to declare what is different.
The pipeline namespace problem. A config can define named pipelines, which are separate transformer chains that are selected by a prefix in the import statement. The jsx: prefix in import Icon from 'jsx:./icon.svg' is a named pipeline declared in .parcelrc under "jsx:*.svg". The pipeline namespace is flatโall named pipelines are in the same objectโand a pipeline can be used by any file that matches its glob. The "jsx:*": ["..."] entry is a common companion to the "jsx:*.svg" entry, because without it, the jsx: prefix on non-SVG files has no pipeline to run . This is a subtle point: the jsx: pipeline for SVGs is declared, but the jsx: pipeline for other files is not, and a file that matches the prefix but not the glob falls through to an error.
The trade-off. The .parcelrc system is powerful because it is compositional. A config can extend a config that extends a config, and each layer can override or extend the behavior of the layers below it. The cost is that the resulting pipeline is not obvious from any single file. A developer who wants to know which transformer processes a .tsx file must trace the extension chain and the glob order. The --log-level verbose flag prints the resolved pipeline for each asset, which is the diagnostic that makes the chain visible .
a. The structure of a .parcelrc file
A .parcelrc file has a small number of top-level fields: extends, resolvers, transformers, packagers, optimizers, reporters, validators, and namers. Each field maps globs or names to plugin arrays. The extends field is the only one that takes a single string, not an array.
// .parcelrc โ a complete configuration with the default fields
{
// Inherit the default pipeline from the default config.
// Without this, nothing works; the default config
// provides the resolvers, transformers, packagers, and optimizers
// that Parcel needs for every file type.
"extends": "@parcel/config-default",
// The resolver chain. The "..." is the default resolver,
// which resolves node_modules and relative paths.
"resolvers": ["@parcel/resolver-default", "..."],
// The transformer map. Each glob maps to a transformer chain.
"transformers": {
"*.{ts,tsx}": ["@parcel/transformer-typescript-tsc"],
"*.{js,jsx}": ["@parcel/transformer-babel", "..."],
"*.svg": ["...", "@parcel/transformer-svg-jsx"],
"jsx:*.svg": ["...", "@parcel/transformer-svg-jsx"]
},
// The packager chain. The default packager is what
// combines the transformed assets into bundles.
"packagers": {
"*.js": "@parcel/packager-js",
"*.css": "@parcel/packager-css",
"*.html": "@parcel/packager-html"
},
// The optimizer chain runs after the packager.
"optimizers": {
"*.js": ["@parcel/optimizer-swc"]
}
}
The extends field is required for a config that wants the default behavior. A config without extends is a complete replacement, not an extension, and every plugin that Parcel needs must be declared explicitly. The "..." syntax is what makes the other fields extend rather than replace. In the transformers map, the "*.svg" entry runs the default SVG transformer ("..."), then the JSX transformer. The "*.{js,jsx}" entry runs Babel, then the default JS transformer. The order within the array is the order the transformers run.
b. Named pipelines and the jsx: prefix
A named pipeline is a transformer chain that is selected by a prefix in the import statement. The prefix is declared as part of the glob in the transformers map, and the pipeline is only used when the import explicitly requests it.
// .parcelrc โ the jsx: pipeline for SVG
{
"extends": "@parcel/config-default",
"transformers": {
// The jsx:*.svg glob matches an import like:
// import Icon from 'jsx:./icon.svg';
// The "..." runs the default SVG transformer first,
// then the JSX transformer converts the SVG to a React component.
"jsx:*.svg": ["...", "@parcel/transformer-svg-jsx"],
// The jsx:* glob is a catch-all for the jsx: prefix.
// Without it, an import with the jsx: prefix but no matching
// glob (a non-SVG file) falls through to an error.
"jsx:*": ["..."]
}
}
The jsx:* entry is not a transformer for JSX files in the ordinary sense. It is a pipeline declaration that says “any import with the jsx: prefix should use the default transformer chain.” The jsx:*.svg entry is a more specific glob that overrides the catch-all for SVG files. The order of the keys matters: jsx:*.svg is checked before jsx:*, so the more specific pipeline wins. This is the same glob priority rule that applies to the ordinary transformer map, and it is the reason the specific entry is listed first.
The named pipeline mechanism is not limited to SVG. A pipeline can be declared for any file type and used with any prefix. A url: pipeline could transform an asset into a URL string, a text: pipeline could transform a file into a raw string, and a bundle: pipeline could transform a file into a bundle reference. The pipeline is a general mechanism for selecting a different transformer chain based on the import syntax .
Complete Example Session
// ============================================
// PART 1: THE MINIMAL .parcelrc
// ============================================
// .parcelrc โ the smallest config that works
{
// Extend the default config.
// Without this, Parcel has no resolvers, transformers, or packagers.
"extends": "@parcel/config-default"
}
// ============================================
// PART 2: THE SVG JSX PIPELINE
// ============================================
// .parcelrc โ adding a named pipeline for SVG
{
"extends": "@parcel/config-default",
"transformers": {
// The jsx:*.svg glob selects the pipeline for 'jsx:./icon.svg'.
// The "..." runs the default SVG transformer first.
"jsx:*.svg": ["...", "@parcel/transformer-svg-jsx"],
// The catch-all for the jsx: prefix.
"jsx:*": ["..."]
}
}
// ============================================
// PART 3: THE BUGGY CONFIG โ MISSING "..."
// ============================================
// .parcelrc โ โ a config that breaks SVG processing
{
"extends": "@parcel/config-default",
"transformers": {
// Without "...", the default SVG transformer is replaced.
// The SVG is passed directly to the JSX transformer,
// which expects a parsed SVG, not a raw file.
"*.svg": ["@parcel/transformer-svg-jsx"]
}
}
// The build may fail, or the output may be incorrect,
// because the default transformer never ran.
// ============================================
// PART 4: THE TRANSFORMER INSERTION ORDER
// ============================================
// .parcelrc โ inserting Babel before the default JS transformer
{
"extends": "@parcel/config-default",
"transformers": {
// Babel runs first, then the default JS transformer.
"*.js": ["@parcel/transformer-babel", "..."]
}
}
// The default JS transformer is still present because of "...".
// Without it, the default JS transformer is replaced.
// ============================================
// PART 5: THE RESOLVER CHAIN
// ============================================
// .parcelrc โ adding a custom resolver
{
"extends": "@parcel/config-default",
"resolvers": ["@parcel/resolver-glob", "..."]
}
// The glob resolver runs first, then the default resolver.
// If the glob resolver does not handle the specifier,
// the default resolver handles it.
// ============================================
// PART 6: THE NAMER
// ============================================
// .parcelrc โ a custom namer for output filenames
{
"extends": "@parcel/config-default",
"namers": ["@parcel/namer-default"]
}
// The namer determines the output filename for each bundle.
// The default namer uses the content hash.
// A custom namer can use a different naming scheme.
// ============================================
// PART 7: THE MULTIPLE EXTENSION CHAIN
// ============================================
// .parcelrc โ extending a project-specific config
{
"extends": "./.parcelrc.base",
"transformers": {
// This config adds a transformer to the chain.
// The base config provides the rest.
"*.md": ["@parcel/transformer-md"]
}
}
// .parcelrc.base โ the project-specific base
{
"extends": "@parcel/config-default",
"transformers": {
"*.tsx": ["@parcel/transformer-typescript-tsc"]
}
}
// The resolution is depth-first: the project config
// is checked first, then the base config, then the default.
// The first match in the chain wins.
// ============================================
// PART 8: THE VERBOSE DIAGNOSTICS
// ============================================
// Run with verbose logging to see the resolved pipeline:
// parcel build src/index.html --log-level verbose
//
// The output prints the transformer chain for each asset.
// This is how you debug a config that is not working.
// ============================================
// PART 9: THE NAMED PIPELINE FOR TEXT
// ============================================
// .parcelrc โ a text: pipeline
{
"extends": "@parcel/config-default",
"transformers": {
// The text:*.md glob selects the pipeline for 'text:./README.md'.
"text:*.md": ["@parcel/transformer-raw"],
"text:*": ["..."]
}
}
// The raw transformer returns the file contents as a string.
// The import statement requests the pipeline with the text: prefix.
// ============================================
// PART 10: VERIFICATION
// ============================================
// [ ] The config extends "@parcel/config-default" or a chain that does.
// [ ] Every custom transformer includes "..." unless it is a full replacement.
// [ ] The glob order places specific patterns before general ones.
// [ ] The named pipeline has a catch-all entry for the prefix.
// [ ] The verbose log shows the expected transformer chain.
The ten parts covered the minimal config, the SVG pipeline, the missing "..." bug, the insertion order, the resolver chain, the namer, the extension chain, the verbose diagnostics, the text pipeline, and the verification checklist. The through-line is that .parcelrc is a compositional config, and the "..." syntax is what makes composition work.
Quick Reference
Top-level fields
| Field | Type | Purpose |
|---|---|---|
extends | string | Parent config to inherit from |
resolvers | string[] | Resolver chain |
transformers | Record<glob, string[]> | Transformer chains by glob |
packagers | Record<glob, string> | Packager by output type |
optimizers | Record<glob, string[]> | Optimizer chains |
namers | string[] | Output filename namers |
reporters | string[] | Build reporters |
validators | Record<glob, string[]> | Validators by glob |
The "..." syntax
| Form | Behavior |
|---|---|
["...", "plugin"] | Default pipeline first, then plugin |
["plugin", "..."] | Plugin first, then default pipeline |
["plugin"] | Plugin replaces the default pipeline |
Named pipeline syntax
| Glob | Matches |
|---|---|
jsx:*.svg | import Icon from 'jsx:./icon.svg' |
jsx:* | Any jsx: import without a more specific match |
text:*.md | import text from 'text:./README.md' |
Best Practices
โ Do This:
// Always extend the default config
"extends": "@parcel/config-default" // โ
// Use "..." to keep the default pipeline
"*.svg": ["...", "@parcel/transformer-svg-jsx"] // โ
// Order specific globs before general ones
"icons/*.svg": ["...", "@parcel/transformer-svg-jsx"], // โ
"*.svg": ["..."] // โ
// Add a catch-all for the named pipeline prefix
"jsx:*": ["..."] // โ
โ Don’t Do This:
// Replace the default pipeline by omitting "..."
"*.svg": ["@parcel/transformer-svg-jsx"] // โ
// Forget the catch-all for the named pipeline
"jsx:*.svg": ["..."] // no "jsx:*" entry // โ
// Put the general glob before the specific one
"*.svg": ["..."], "icons/*.svg": ["..."] // โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| SVG processing breaks after adding JSX | "..." omitted from the transformer chain | Add "..." |
| Named pipeline fails for non-SVG files | No jsx:* catch-all entry | Add "jsx:*": ["..."] |
| Specific glob is ignored | General glob listed first | Move the specific glob above the general one |
| Config has no effect | extends missing | Add "extends": "@parcel/config-default" |
| Plugin order is wrong | Array order not considered | Put the plugin before or after "..." as needed |
Real-World Examples
1. Minimal config
{ "extends": "@parcel/config-default" }
2. SVG JSX pipeline
"jsx:*.svg": ["...", "@parcel/transformer-svg-jsx"]
3. Catch-all for the prefix
"jsx:*": ["..."]
4. Babel before default JS
"*.js": ["@parcel/transformer-babel", "..."]
5. Custom resolver
"resolvers": ["@parcel/resolver-glob", "..."]
6. TypeScript transformer
"*.{ts,tsx}": ["@parcel/transformer-typescript-tsc"]
7. Raw text pipeline
"text:*.md": ["@parcel/transformer-raw"]
8. Extending a project config
{ "extends": "./.parcelrc.base" }
9. Verbose diagnostics
parcel build src/index.html --log-level verbose
10. Optimizer chain
"optimizers": { "*.js": ["@parcel/optimizer-swc"] }
Visual
The Extension Chain
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ HOW PARCEL RESOLVES A CONFIG โ
โ โ
โ .parcelrc (project) โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ extends: "./base" โ โ
โ โ transformers: โ โ
โ โ "*.md": [raw] โ โ checked first โ
โ โโโโโโโโโโโโฌโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ .parcelrc.base โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ extends: default โ โ
โ โ transformers: โ โ
โ โ "*.tsx": [tsc] โ โ checked second โ
โ โโโโโโโโโโโโฌโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ @parcel/config-default โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ transformers: โ โ
โ โ "*.js": [...] โ โ checked third โ
โ โ "*.css": [...] โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ The first match in the chain wins. โ
โ "..." means "continue to the next config in the chain." โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The "..." Syntax
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ WITH AND WITHOUT "..." โ
โ โ
โ ["...", "plugin"] โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Default pipeline โ โ runs first โ
โ โ Plugin โ โ runs second โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ ["plugin", "..."] โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Plugin โ โ runs first โ
โ โ Default pipeline โ โ runs second โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ ["plugin"] โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Plugin โ โ runs alone โ
โ โ (default replaced) โ โ default pipeline is gone โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ The placement determines the order. โ
โ The presence determines whether the default survives. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Named Pipeline
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE jsx: PREFIX โ
โ โ
โ import Icon from 'jsx:./icon.svg' โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Parcel reads the โ โ
โ โ "jsx:" prefix โ โ
โ โโโโโโโโโโโโฌโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Checks the glob โ โ
โ โ "jsx:*.svg" โ โ specific match โ
โ โโโโโโโโโโโโฌโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Runs the chain: โ โ
โ โ "..." + svg-jsx โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ If "jsx:*.svg" does not match, "jsx:*" is checked. โ
โ If neither matches, the import falls through to an error. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Glob Priority
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ORDER MATTERS, NOT SPECIFICITY โ
โ โ
โ โ Wrong order: โ
โ "*.svg": ["..."], โ
โ "icons/*.svg": ["...", "icon-plugin"] โ
โ โ "icons/star.svg" matches "*.svg" first, โ
โ the icon plugin never runs. โ
โ โ
โ โ
Correct order: โ
โ "icons/*.svg": ["...", "icon-plugin"], โ
โ "*.svg": ["..."] โ
โ โ "icons/star.svg" matches "icons/*.svg" first, โ
โ the icon plugin runs. โ
โ โ "logo.svg" falls through to "*.svg". โ
โ โ
โ The first match in the object wins. โ
โ The object order is the priority order. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| File format | JSON5 (comments, unquoted keys, trailing commas) |
| Required field | extends for default behavior |
| Extension syntax | "..." embeds the next-priority pipeline |
| Named pipeline | Prefix in glob (jsx:*.svg) |
| Catch-all for prefix | "jsx:*": ["..."] |
| Glob priority | Object key order, first match wins |
| Diagnostics | --log-level verbose |
Key takeaways:
- The
"..."syntax is the mechanism for extending, not replacing. A transformer array without"..."replaces the default pipeline for the matched files, which breaks the default transformations. Most plugin configurations should include"..."before or after the plugin, depending on the desired order . - The
extendsfield is required for the default pipeline. A.parcelrcwithoutextendsis a complete replacement, not an extension, and every plugin Parcel needs must be declared explicitly. The typical config extends@parcel/config-defaultor a chain that does . - Glob order is positional, not specificity-based. The first matching glob in the object wins. A specific pattern like
"icons/*.svg"must be listed before the general"*.svg"pattern, or the specific transformer never runs . - Named pipelines require a catch-all. The
"jsx:*.svg"entry handles SVG files imported with thejsx:prefix, but the"jsx:*"entry is what handles the prefix for files that do not match the specific glob. Without it, an import with the prefix but no matching pipeline falls through to an error . - The verbose log is the debugging tool. The
--log-level verboseflag prints the resolved transformer chain for each asset. When a config is not working, the log shows which glob matched and which plugins ran .
Remember: .parcelrc is a compositional config, not a complete pipeline declaration. The default config provides the baseline, the extends chain provides the project-specific overrides, and the "..." syntax embeds the next-priority pipeline at the right position. The two failure modes are replacing instead of extending (omitting "...") and ordering the globs incorrectly (general before specific). The verbose log shows both. The config is optional, but when it is needed, the extension model is what makes it maintainable.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!