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.