How Prettier Formats JavaScript with an AST Printer
Prettier is an opinionated code formatter that enforces a consistent style across codebases by parsing source code into an Abstract Syntax Tree (AST) and reprinting it from scratch. Rather than tweaking existing whitespace or applying superficial regex rules, Prettier ignores original formatting entirely and recalculates line breaks, wrapping, and indentation based on a strict set of layout rules and a configurable maximum line length.
What is Prettier?
Prettier is an automated code formatting tool widely used in JavaScript, TypeScript, and modern web development. Unlike traditional linters like ESLint—which primarily flag errors, anti-patterns, and stylistic deviations—Prettier’s sole focus is outputting fully formatted code. It is deliberately “opinionated,” offering minimal configuration options to eliminate team debates over code style, such as where to place newlines, whether to use single or double quotes, or how to indent chained methods.
Understanding the AST (Abstract Syntax Tree)
To understand how Prettier works, it is essential to understand the Abstract Syntax Tree (AST). An AST is a hierarchical tree representation of the syntactic structure of source code.
When JavaScript code is passed to a parser (such as Babel or Flow,
which Prettier uses under the hood), the parser breaks the code down
into tokens and organizes them into nodes. For example, a variable
declaration const sum = 1 + 2; is parsed into a tree of
nodes representing the declaration type, the identifier
(sum), the operator (+), and the literal
values (1, 2).
Crucially, an AST retains the semantic meaning of the code while disregarding stylistic elements like extra whitespace, blank lines, and original indentation.
How the Opinionated AST Printer Works
Prettier processes and formats JavaScript through a multi-step pipeline:
1. Parsing into an AST
The source JavaScript is read and converted into an AST. During this phase, comments are extracted and attached to the closest relevant AST nodes to ensure they are not lost during reconstruction.
2. Discarding Original Styling
Prettier discards all original styling—including spaces, tabs, and manual line breaks. This complete reset is why Prettier is deterministic; the same AST will always yield the exact same output regardless of how messy the input was.
3. Converting the AST to an Intermediate Document Representation
Prettier transforms the AST into an internal intermediate representation (IR), often referred to as a “Doc.” This Doc consists of structural primitives, such as: * Concat: Items that should be rendered sequentially. * Group: A collection of items that should either all stay on one line or all break into multiple lines. * Line: A potential line break that turns into a newline if the surrounding group does not fit on one line, or a space if it does. * Indent: Marks a block of code to be indented relative to the current level.
4. Layout and Line Measurement
Prettier’s printing engine evaluates the Doc against a target maximum
line length (known as printWidth, defaulting to 80
characters). The printer calculates the length of each group: * If a
group fits within the remaining space on the line, it is printed inline
on a single line. * If a group exceeds the line limit, it expands,
triggering the line breaks defined inside that group and indenting the
nested elements accordingly.
5. Final Code Generation
The printer writes the formatted string output based on the calculated layout decisions, re-attaching comments in their correct contextual locations.
Why the AST Printer Approach Is Effective
Traditional formatters often struggle with edge cases because they attempt to modify existing strings of code. By tearing the code down to an AST and generating a brand new string layout, Prettier guarantees structural consistency. Long function signatures, complex ternary operators, and deeply nested objects are automatically reformatted into clean, multi-line structures when they grow too long, and collapsed into compact, single-line structures when they are short, ensuring full syntactic safety and uniform readability across large codebases.