Formatter
Biome is an opinionated formatter that has the goal to stop all ongoing debates over styles. It follows a similar philosophy to Prettier, only supporting a few options to avoid debates over styles, turning into debates over Biome options. It deliberately resists the urge to add new options to prevent bike-shed discussions in teams so they can focus on what really matters instead.
Options
The language agnostic options supported by Biome are:
- indent style (default:
tab
): Use spaces or tabs for indention - tab width (default:
2
): The number of spaces per indention level - line width (default:
80
): The column width at which Biome wraps code
Other formatting options are available for specific languages as well. See the configuration options for details.
Use the formatter with the CLI
By default, the formatter checks the code and emit diagnostics if there are changes in formatting:
- npm
- yarn
- pnpm
- bun
- deno
npx @biomejs/biome format ./src
yarn dlx @biomejs/biome format ./src
pnpm dlx @biomejs/biome format ./src
bunx @biomejs/biome format ./src
deno run -A npm:@biomejs/biome format ./src
If you want to apply the new formatting, pass the --write
option:
- npm
- yarn
- pnpm
- bun
- deno
npx @biomejs/biome format --write ./src
yarn dlx @biomejs/biome format --write ./src
pnpm dlx @biomejs/biome format --write ./src
bunx @biomejs/biome format --write ./src
deno run -A npm:@biomejs/biome format --write ./src
Use the --help
flag to know what are the available options:
- npm
- yarn
- pnpm
- bun
- deno
npx @biomejs/biome format --help
yarn dlx @biomejs/biome format --help
pnpm dlx @biomejs/biome format --help
bunx @biomejs/biome format --help
deno run -A npm:@biomejs/biome format --help
Or check the CLI reference section.
Configuration
You may want to configure Biome using biome.json
.
The following defaults are applied:
{ "formatter": { "enabled": true, "formatWithErrors": false, "indentStyle": "tab", "indentWidth": 2, "lineWidth": 80, "ignore": [] }}
Ignoring Code
There are times when the formatted code isn’t ideal.
For these cases, you can use a format suppression comment:
// biome-ignore format: <explanation>
Example:
const expr = // biome-ignore format: the array should not be formatted [ (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, -(f + n) / (f - n), -(2 * f * n) / (f - n), 0, 0, -1, 0, ];
Differences with Prettier
There are some divergences with Prettier.
Bogus or duplicate modifiers on class properties
Input
// Multiple accessibility modifiersclass Foo { private public a = 1;}
// Declare function with bodydeclare function foo ( ) { }
// Invalid use of abstractclass Bar { abstract foo ;}
// Duplicate Readonlyclass Read { readonly readonly x: number;}
Diff
// Multiple accessibility modifiersclass Foo { private a = 1; private public a = 1;}
// Declare function with bodydeclare function foo() {};declare function foo ( ) { }
// Invalid use of abstractclass Bar { abstract foo; abstract foo ;}
// Duplicate Readonlyclass Read { readonly x: number; readonly readonly x: number;}
Reason
Prettier’s Babel-based parsing for JS/TS is very loose and allows multiple errors to be ignored. Biome’s parser intentionally has stricter rules than Prettier and correctly asserts that the statements in these tests are invalid. Duplicate modifiers for functions are not semantically valid, function declarations are not allowed to have bodies, non-abstract classes cannot have abstract properties, etc.
In Prettier, these errors aren’t considered parse errors, and the AST is still built “correctly” with the appropriate nodes. When formatting, Prettier then just treats these nodes as normal and formats them accordingly.
In Biome, the parsing errors result in Bogus
nodes, which may contain any number of valid nodes, invalid nodes, and/or raw tokens. When formatting, Biome treats bogus nodes as effectively plain text, printing them out verbatim into the resulting code without any formatting, since attempting to format could be incorrect and cause semantic changes.
For class properties, Prettier’s current parsing strategy also uses boolean fields for modifiers, meaning only one of each kind of modifier can ever be present (accessibility modifiers are stored as a single string). When printing, Prettier just looks at the list of booleans and decides which modifiers to print out again. Biome instead keeps a list of modifiers, meaning duplicates are kept around and able to be analyzed (hence the parsing error messages about duplicate modifiers and ordering). When printing out the bogus nodes, this list is still kept intact, and printing out the unformatted text results in those modifiers continuing to exist.
There are ways that Biome can address this. One possibility is to try to interpret the Bogus nodes when formatting and construct valid nodes out of them. If a valid node can be built, then it would just format that node like normal, otherwise it prints the bogus text verbatim as it does currently. However, this is messy and introduces a form of parsing logic into the formatter that is really not meaningful.
Another option instead is to introduce some form of “syntactically-valid bogus node” into the parser, which accepts these kinds of errors that are purely semantic (duplicate modifiers, abstract properties in non-abstract classes). It would continue to build the nodes like normal (effectively matching the behavior in Prettier), but store them inside of a the new kind of bogus node, including the diagnostics along with it. When formatting, these special bogus nodes would just attempt to format the inner node, and then fallback if there’s an error (the existing format_or_verbatim
utility would do this already). This keeps the parsing and formatting logic separate from each other, but introduce more complexity to the parser, allowing invalid states to be considered semi-valid.
Prettier doesn’t unquote some object properties that are valid JavaScript identifiers.
const obj = { 'a': true, b: true, "𐊧": true,}
Diff
const obj = { a: true, b: true, "𐊧": true, 𐊧: true,};
Reason
Prettier and Biome unquote object and class properties that are valid JavaScript identifiers. Prettier unquotes only valid ES5 identifiers.
In an ecosystem where ES2015 is now widespread, this seems to be a legacy restriction. Thus, we decided to diverge here by unquoting all valid JavaScript identifiers in ES2015+.
A possible workaround would be to introduce a configuration to set the ECMAScript version a project uses.
We could then adjust the unquoting behaviour based on that version.
Setting the ECMAScript version to ES5
could match the behaviour of Prettier.
Prettier has an inconsistent behavior for assignment in computed keys.
Input
a = { [this.resource = resource]: 1,}
Diff
a = { [(this.resource = resource)]: 1, [this.resource = resource]: 1,};
Reason
Prettier and Biome enclose some assignment expressions between parentheses, in particular in conditionals. This allows to identify potentially an expression that should be a comparison.
Prettier has an inconsistent behavior, because it adds parentheses for an assignment in a computed key of an object property and doesn’t for a computed key of a class property, as demonstrated by the following example:
Input
a = { [x = 0]: 1,}
class C { [x = 0] = 1}
Output
a = { [(x = 0)]: 1,};
class C { [x = 0] = 1;}
To be consistent, we decide to diverge and omit the parentheses. Alternatively, we could enclose any assignment in a computed key of an object or of a class.
Prettier accepts an incorrect modifier for the type parameters of an interface.
Input
interface L<in const T> {}
Diff
interface L<const in T> {}interface L<in const T> {}
Reason
As mentioned in a previous divergence, Prettier’s Babel-based parsing for JS/TS is very loose and allows multiple errors to be ignored. Biome’s parser intentionally has stricter rules than Prettier and correctly asserts that the const
modifier is not allowed for type parameters of interfaces.
In Prettier, this error isn’t considered a parse error, and the AST is still built “correctly” with the appropriate nodes. When formatting, Prettier then just treats these nodes as normal and formats them accordingly.
In Biome, the parsing errors result in a Bogus node, which may contain any number of valid nodes, invalid nodes, and/or raw tokens. When formatting, Biome treats bogus nodes as effectively plain text, printing them out verbatim into the resulting code without any formatting, since attempting to format could be incorrect and cause semantic changes.
Prettier adds a trailing comma to type parameters of arrow functions even when it is not required.
Input
<T = unknown>() => {};
Diff
<T = unknown,>() => {};<T = unknown>() => {};
Reason
In some specific cases, a type parameter list of an arrow function requires a trailing comma to distinguish it from a JSX element. When a default type is provided, this trailing comma is not required. Here, we diverge from Prettier, because we think it better respects the original intent of Prettier, which was to add a trailing comma only when required.