Babel Cheat Sheet
Covers Babel configuration files, presets and plugins, browserslist targets, polyfills, and CLI commands for transpiling modern JavaScript.
babel.config.js
Project-wide presets and plugins.
// babel.config.jsmodule.exports = { presets: [ ['@babel/preset-env', { targets: '> 0.25%, not dead' }], '@babel/preset-react', '@babel/preset-typescript', ], plugins: [ '@babel/plugin-transform-runtime', // avoids duplicated helpers in output ],};
Presets in Practice
How preset-env transforms modern syntax for older targets.
// npm install --save-dev @babel/core @babel/preset-env @babel/cli// Input (modern JS)const greet = (name) => `Hello, ${name}!`;// preset-env transforms output based on browserslist targets, e.g.:"use strict";var greet = function greet(name) { return "Hello, ".concat(name, "!");};
CLI Usage
Transpiling files and directories from the terminal.
npx babel src --out-dir lib # transpile a directorynpx babel script.js --out-file out.js # transpile a single filenpx babel src --watch --out-dir lib # watch modenpx babel-node src/index.js # run without a separate compile step
Core Concepts
The pieces that make up the Babel toolchain.
- @babel/core- the compiler engine that parses, transforms, and generates code
- preset-env- bundles the plugins needed to support a given set of target browsers
- browserslist- shared config (e.g. a browserslist field or .browserslistrc file) that determines what preset-env targets
- plugin- a single transform, e.g. plugin-transform-arrow-functions
- polyfill (core-js)- adds missing runtime APIs like Promise or Array.flat that syntax transforms alone can't provide
- AST (Abstract Syntax Tree)- the intermediate representation Babel parses code into before transforming it
Writing a Custom Plugin
The visitor pattern used to write your own Babel transform.
// my-babel-plugin.jsmodule.exports = function myPlugin({ types: t }) { return { name: 'rewrite-console-log', visitor: { CallExpression(path) { const callee = path.get('callee'); if (callee.matchesPattern('console.log')) { callee.get('object').replaceWith(t.identifier('logger')); } }, // Runs once before any node is visited Program: { enter(path, state) { state.opts.verbose && console.log('visiting', state.filename); }, }, }, };};// babel.config.jsmodule.exports = { plugins: [['./my-babel-plugin', { verbose: true }]] };
Programmatic AST Pipeline
Parsing, traversing, and generating code without the CLI.
const parser = require('@babel/parser');const traverse = require('@babel/traverse').default;const generate = require('@babel/generator').default;const t = require('@babel/types');const ast = parser.parse('const x = 1 + 2;', { sourceType: 'module' });traverse(ast, { BinaryExpression(path) { // Fold constant arithmetic at build time if (t.isNumericLiteral(path.node.left) && t.isNumericLiteral(path.node.right)) { const result = path.node.left.value + path.node.right.value; path.replaceWith(t.numericLiteral(result)); } },});const { code } = generate(ast, { retainLines: false });console.log(code); // const x = 3;
Assumptions API for Smaller Output
Trading spec edge-case correctness for leaner compiled code (Babel 7.13+).
// babel.config.jsmodule.exports = { presets: ['@babel/preset-env'], assumptions: { noDocumentAll: true, // skip `document.all` guard in optional chaining setPublicClassFields: true, // use simple assignment for class fields constantSuperCanBeInjected: true, },};// Equivalent to setting `loose: true` on individual plugins,// but centralizes the tradeoff in one place instead of per-plugin flags.
Env-Specific & Per-Directory Overrides
Splitting config by NODE_ENV and by path glob in one file.
// babel.config.jsmodule.exports = { presets: ['@babel/preset-env'], env: { test: { // CommonJS for Jest, ESM everywhere else presets: [['@babel/preset-env', { targets: { node: 'current' } }]], }, production: { plugins: ['transform-remove-console'], }, }, overrides: [ { test: './legacy/**/*.js', presets: [['@babel/preset-env', { targets: { ie: '11' } }]], }, ],};
Advanced Concepts
Terminology that matters once you go past basic transpilation.
- path- a wrapper around an AST node exposing traversal/mutation methods (replaceWith, insertBefore, skip)
- assumptions- config block that lets plugins emit smaller output by dropping rare spec edge cases
- @babel/plugin-transform-runtime- rewrites helpers/globals to imports from @babel/runtime so multiple files don't duplicate helper code
- corejs option- tells preset-env/runtime which core-js major version to pull polyfills from (2 vs 3)
- babel-plugin-macros- lets libraries ship zero-config compile-time transforms without users touching babel.config.js
- path.skip() / path.stop()- visitor control methods to avoid re-visiting a subtree you just replaced or halt traversal entirely
- isTSX / preset-typescript- Babel strips TypeScript types without type-checking; run tsc --noEmit separately for type safety
Set explicit browserslist targets instead of relying on Babel's defaults: an overly broad target list silently bloats your bundle with transforms and polyfills that nobody in your actual audience needs.