- Nov 27, 2025
- Parsed from source:Nov 27, 2025
- Detected by Releasebot:Dec 9, 2025
Prettier 3.7: Improved formatting consistency and new plugin features!
Prettier 3.7 polishes TypeScript and Flow formatting, aligns class and interface outputs, and refines brace printing. It adds Angular 21, GraphQL 16.12, Front Matter for Handlebars, and new plugin APIs while fixing numerous bugs for a smoother dev experience.
Highlights
TypeScript
We are excited to announce Prettier 3.7! This release focuses on polishing the TypeScript and Flow experience, specifically by aligning the formatting of classes and interfaces to be more consistent and predictable. We also want your opinion on the upcoming change to fix inconsistent opening brace print logic of class and interface body.
Additionally, we also fixed lots of bugs, added support for new features in Angular 21 and Graphql 16.12, added Front Matter support to Handlebars.
For plugin developers, we've added new APIs to give you more control over comment attachment and handling of ignored nodes.
If you appreciate Prettier and would like to support our work, please consider sponsoring us directly via our OpenCollective or by sponsoring the projects we depend on. Thank you for your continued support!
Highlights
TypeScript
Fix the inconsistent printing between class and interface (#18094, #18091, #18215 by @fisker)
In this release, we've focused heavily on improving consistency between Class and Interface formatting. Previously, these two similar constructs were printed quite differently, leading to visual inconsistencies. We've aligned their formatting rules to provide a more predictable and cleaner output.The extra indentation for type parameters in class has been removed
Align interface heritages print with class
Align single heritage print with super class
Inconsistent opening brace print logic of class and interface body
In Prettier v2.3, to improve visual separation between class head and body, we started to print the opening { of the class body on a new line when the class has multiple heritages.
However, not everyone is happy with this change.
Let us know what you think about applying this change to interfaces by leaving a comment on this issue.
If you have a better solution for this issue, we'll be happy to discuss it too.
Unless a better solution comes along, we'll align the interface body print with the one for the class body in Prettier v4.Other Changes
JavaScript
Allow break import attributes into multiple lines (#17329 by @fisker)
Add support for "Discard Bindings" proposal (#17708 by @fisker)
The Stage 2 proposal "Discard Bindings" is now supported via Babel. Also keep in mind our policy on non-standardized syntax before using this proposed syntax feature with Prettier.Fix inconsistent comment format (#17723 by @fisker)
Add additional Playwright test functions (#17876 by @BPScott)
Prettier already avoids changing indentation for test functions when you add .skip to them. It now also treats the Playwright functions test.fixme, test.describe.skip and test.describe.fixme similar to test.skip.Avoid break {import,require.resolve,require.resolve.paths,import.meta.resolve}() with long module name (#17882, #17908 by @kovsu & @fisker)
Improve comment handing inside if statement (#17998 by @fisker)
Improve require() call with comments (#18037 by @fisker)
Remove indention in logical expression in Boolean() call (#18087 by @kovsu)
Fix comments handling for for-statements (#18099 by @fisker, @sosukesuzuki)
Improve comment printing around empty statement (#18108 by @fisker)
Fix inconsistent comment print between class methods and object methods (#18147 by @fisker)
Add missing parentheses in bitwise operators (#18163 by @fs0414)
Fix inconsistent break for array literals (#18172 by @Dunqing, @fisker)
Fix inconsistent logical expression print (#18205 by @fisker)
Fix inconsistent print between CallExpression and NewExpression (#18206 by @fisker)
Remove redundant parentheses around JSX element (#18243 by @fisker)
Improve formatting of logical expression as callee of new expression (#18245 by @fisker)
Remove empty line in for statement without "update" (#18300 by @fisker)
Improve super class format (#18325 by @fisker)
TypeScript
Fix misplacement of comments after arrow (#17421 by @o-m12a, @t-mangoe)
Fix TSMappedType format (#17785 by @fisker)
Print trailing comma in TSImportType options (#17798 by @fisker)
Fix inconsistent comment printing between typescript and flow parser (#18110 by @fisker)
Fix missing semicolon before call signatures (#18118 by @fisker)
Fix inconsistent print of as const between flow and typescript parsers (#18161 by @fisker)
Fix comment around as/satisfies expression (#18162 by @fisker)
Add missing parentheses to arrow function in instantiation expression (#17724 by @fisker)
CSS
Handle attribute selector with case-sensitive and uppercase case-insensitive flags (#17841, #17865 by @kovsu)
Fix crash when formatting special custom properties (#17899 by @fisker)
Fix selector been lowercased incorrectly inside css modules (#17929 by @kovsu)
Fix formatting of CSS selectors contains // (#17938 by @kovsu)
Remove unexpected space between font size and line height (#18114 by @kovsu)
Fix extra indent for CSS comma-separated values after a block comment (#18228 by @seiyab)
SCSS
Fix parentheses space problem in mixin argument (#17836 by @kovsu)
Fix formatting of space-separated values (#17903 by @kovsu)
Less
Fix variable name being lowercased incorrectly (#17820 by @kovsu)
Keep property/variable accessors tight (#17983 by @kovsu)
HTML
Support format allow attribute of iframe element (#17879 by @kovsu)
Format inline event handler (#17909 by @kovsu)
Angular
Support Angular 21 (#17722, #18294 by @fisker)
Angular 20.1 added support for new assignment operators. Angular 21 added support for regular expression.Fix comments get duplicated in interpolation (#17862 by @fisker)
Ember / Handlebars
Added Front Matter support to Handlebars (#17781 by @Codezilluh)
Front matter can now be used in Handlebars.Preserve else if syntax for custom helpers (#17856 by @kovsu)
Remove extra blank lines in
Original source Report a problem - Jun 23, 2025
- Parsed from source:Jun 23, 2025
- Detected by Releasebot:Dec 9, 2025
Prettier 3.6: Experimental fast CLI and new OXC and Hermes plugins!
Prettier unveils a high‑performance experimental CLI behind --experimental-cli and ships two official plugins: @prettier/plugin-oxc and @prettier/plugin-hermes. The update adds broad language parser improvements and fixes across JS, TS, CSS, HTML and more.
Highlights
CLI
Support experimental CLI (#17151, #17396 by @fisker)
You may have already heard of or used our new performance improved CLI. From Prettier 3.6, you can now use it without installing unstable v4 version.# Run CLI with `--experimental-cli` prettier --check --experimental-cli # Or use environment variable `PRETTIER_EXPERIMENTAL_CLI=1` PRETTIER_EXPERIMENTAL_CLI=1 prettier --checkJavaScript
Added a new official plugin @prettier/plugin-oxc (#17472, #17483 by @fisker)
@prettier/plugin-oxc is based on OXC (A fast JavaScript and TypeScript parser in Rust).
This plugin includes two new parsers oxc (JavaScript syntax) and oxc-ts (TypeScript syntax), to use this plugin:- Install the plugin
- yarn add --dev prettier @prettier/plugin-oxc
- Add the following to your .prettierrc file
- plugins:
- "@prettier/plugin-oxc"
Due to package size limitations, this plugin is not included in the prettier package, it needs to be installed separately.
For more information, check the package homepage.
Many thanks to the OXC team(@boshen, @overlookmotel, and other contributors).
Flow
Added a new official plugin @prettier/plugin-hermes (#17520 by @fisker)
@prettier/plugin-hermes is based on Hermes JS Engine.
This plugin includes a new parser hermes (Flow syntax), to use this plugin:- Install the plugin
- yarn add --dev prettier @prettier/plugin-hermes
- Add the following to your .prettierrc file
- plugins:
- "@prettier/plugin-hermes"
Due to package size limitations, this plugin is not included in the prettier package, it needs to be installed separately.
We plan to make this as the default parser for Flow syntax support in v4, we'll also remove babel-flow parser in v4, please give it a try.
For more information, check the package homepage.
Many thanks to the Hermes team.
Other Changes
JavaScript
- Add parentheses to SequenceExpression in ReturnStatement and ExpressionStatement (#17085 by @TYKevin)
- Add parentheses to AssignmentExpression in class property keys (#17145 by @fisker)
- Add parentheses to numbers in optional member expression (#17190 by @fisker)
- Removed support for experimental Records & Tuples (#17363 by @fisker)
- Preserve spaces between CSS words and embedded expression (#17398 by @sosukesuzuki)
- Fix inconsistent assignment format (#17469 by @fisker)
- Fix inconsistent member chain format (#17470 by @fisker)
- Fix optional chaining as computed key (#17486 by @fisker)
- Support type cast comments for acorn and meriyah parser (#17491, #17566 by @ArnaudBarre, #17600 by #fisker)
- Fix unstable comment format in tagged template literal (#17510 by @fisker)
- Improve consistency for JSX in optional method call (#17616 by @seiyab)
TypeScript
- Support import type attribute in TSImportType (#16881 by @fisker)
- Fix comments in logical expression and intersection type (#17193 by @fisker)
- Improve new line detect in mapped type (#17498 by @fisker)
- Don't print extra semicolon after prettier-ignored index-signature (#17538 by @sosukesuzuki)
- Fix missing parentheses in ConditionalTypeAnnotation (#17196 by @fisker)
JSON
- Allow format comment-only JSONC files (#17269 by @fisker)
- Forbid parenthesized expressions (#17598 by @fisker)
CSS
- Support @utility directive for Tailwind (#17362 by @sosukesuzuki)
- Remove extra indentation for :has pseudo call (#17541 by @sosukesuzuki)
Less
- Fix function argument incorrectly lowercased (#17502 by @fisker)
HTML
- Fix formatting when tag name is an object prototype property (#17501 by @fisker)
Angular
- Support TemplateLiteral introduced in Angular 19.2 (#17238 by @fisker)
- Remove extra colon after track in angular @for control-flow (#17280 by @claudio-herger)
- Support Angular 20 (#17534 by @fisker)
MJML
- Enabling CSS formatting within tag (#17338 by @iryusa)
- Correctly parse and (#17400 by @fisker)
Markdown
- Fix adjacent markdown syntax in blockquote (#16596 by @fiji-flo)
- Fix strong emphasis (#17143 by @fiji-flo)
YAML
- Do not add line break before empty map or sequence (#16074 by @BapRx)
API
- Accept URL in plugins option (#17166 by @fisker)
- Accept URL as custom config file in resolveConfig (#17167 by @fisker)
CLI
- Forbid use --config and --no-config together (#12221 by @Balastrong)
- Ignore file modified time when --cache-strategy=content (#17438 by @fisker)
- Fix result message for files can not be formatted (#17505 by @fisker)
- Fix exitCode when parser cannot infer (#17505 by @fisker)
- Fix plugin loading in prettier.getFileInfo() (#17548 by @fisker)
- Allow plugin to override builtin parsers when inferring parser (#17549 by @fisker)
Miscellaneous
- Add isSupported function support for languages API (#17331 by @JounQin, #17490 by @fisker)
- Fix embedded format with cursorOffset (#17254 by @fisker)
- Feb 9, 2025
- Parsed from source:Feb 9, 2025
- Detected by Releasebot:Dec 9, 2025
Prettier 3.5: New objectWrap option, experimentalOperatorPosition option and TS config file support!
Prettier rolls out new options objectWrap and experimentalOperatorPosition along with first class TypeScript config file support. The release also includes numerous bug fixes and tweaks across JavaScript, CSS, Vue, Angular, Markdown and more. Note that some options are experimental and may change in future updates.
This release includes a lot of bug fixes and the following new features:
- Support for the new objectWrap option
- Support for the new experimentalOperatorPosition option
- Support for TypeScript configuration file
See each section for details.
If you appreciate Prettier and would like to support our work, please consider sponsoring us directly via our OpenCollective or by sponsoring the projects we depend on, such as typescript-eslint, remark, and Babel. Thank you for your continued support!
Why We Added Two New Options
This release introduces two new options. If you’re familiar with Prettier’s Option Philosophy, you might be wondering: “Why add new options?” Rest assured, these aren’t your typical options, nor do they violate our option philosophy.
As the name suggests, experimentalOperatorPosition is experimental. We have a policy for experimental options, which means it will eventually be removed. In the future, the new behavior could become the default, or this option might be dropped entirely. If you’ve been following Prettier for a while, you may recall we once added an experimentalTernaries option, and this follows the same approach.
objectWrap is a bit special. For a long time, we’ve struggled with how to print multi-line objects. We haven’t yet found the perfect solution, so we’ve resorted to a semi-manual approach. For more details, see our Rationale. The current behavior isn’t ideal because the final output can vary based on how the user writes their code. To provide a more consistent format, we’ve decided to introduce the objectWrap option.
Although this release includes two new options, we want to emphasize that we haven’t forgotten Prettier’s option philosophy. These options address specific, long-standing formatting challenges without compromising our option philosophy.Highlights
JavaScript
Add experimental option for breaking lines before binary operators (#7111 by @btmills)
This is implemented behind the --experimental-operator-position <start|end> flag.
When binary expressions wrap lines, start prints the operators at the start of new lines. Placing binary operators at the beginning of wrapped lines can make the operators more prominent and easier to scan.Implement objectWrap config option (#16163 by @pauldraper, @sosukesuzuki)
Prettier has historically done semi-manual formatting of multi-line JavaScript object literals.
Namely, an object is kept on multiple lines if there is a newline prior to the first property, even if it could fit on a single line. See Multi-line objects for more details.
While this behavior continues to be the default, --object-wrap=collapse instead ignores whitespace when formatting object literals.Add support for TypeScript config files (#16828 by @itsyoboieltr & @fisker)
Added new format of configuration files:- .prettierrc.ts
- .prettierrc.mts
- .prettierrc.cts
- prettier.config.ts
- prettier.config.mts
- prettier.config.cts
Note:
Currently TypeScript support in Node.js is experimental.
To make TypeScript config files work, Node.js>=22.6.0 is required and Node.js v22 requires --experimental-strip-types.
You can run prettier with
node --experimental-strip-types node_modules/prettier/bin/prettier.cjs --writeor
NODE_OPTIONS="--experimental-strip-types" prettier --writeOther TS loaders should also work, but not tested, use at your own risk.
For example, with tsx, you cannode --import tsx node_modules/prettier/bin/prettier.cjs --writeor
tsx node_modules/prettier/bin/prettier.cjs --write
Other Changes
JavaScript
Improve word wrapping edge cases in JSX (#16700 by @seiyab)Flow
Support const type parameters in Flow (#16947 by @gkz)CSS
Break before breaking comma separated values (#16907 by @seiyab)Vue
Support .prop shorthand (#16920 by @fisker)Angular
Improve line breaks inside ICU blocks (#16922 by @fisker)
Fix extra new line inside ICU blocks (#16922 by @fisker)Ember / Handlebars
Handle
- Nov 26, 2024
- Parsed from source:Nov 26, 2024
- Detected by Releasebot:Dec 9, 2025
Prettier 3.4: A lot of bug fixes
Prettier ships a broad bug fix release touching JavaScript, TypeScript, CSS, HTML, Markdown and more. It includes improved comment preservation, top level await support, and a range of formatting fixes plus API tweaks.
Other Changes
JavaScript
Fix template literal print with array (#13315 by @fisker, @syi0808)
Add missing parentheses in tagged template literals (#16500 by @syi0808)
Don't remove useless \ in string literals (#16563 by @sosukesuzuki, #16763 by @fisker)
Previously, Prettier would remove useless escape characters () from string literals. However, this behavior was inconsistent as it did not apply to template literals, which was reported in issue #16542.
This issue is a feature request to extend this behavior to template literals as well.
After discussing this internally, the Prettier team concluded that removing useless escape characters, whether in string literals or template literals, is the responsibility of a linter, not a formatter.
This change disables the removal of useless escape characters in string literals across all languages supported by Prettier. To keep the previous behavior, we recommend using ESLint rules like no-useless-escape.
Escaped quotes (e.g. ""'" ) may get unescaped when changing between different quotes. This is explained on the Rationale page of the official documentation.Improve comment formatting for logical expression in unary expression (#16593 by @sosukesuzuki)
Removed support for experimental syntax (#16643, #16705 by @fisker)
- DecimalLiteral - The Decimal proposal decided not to introduce new syntax. The decimal plugin will be removed from Babel 8.
- importReflection - The "Import Reflection" proposal has been renamed to "Source Phase Imports"
- Disclaimer about non-standard syntax
TypeScript
Add missing parentheses in tagged template literals (#16500 by @syi0808)
Preserve a comment on between decorator and modified parameter property (#16574 by @sosukesuzuki)
The current version of Prettier unexpectedly moves a line comment between a parameter property modified by readonly, private, public, etc and a decorator. This output results in invalid TypeScript code.
This change ensures that the original format is preserved.Preserve a comment between modifier and the decorated property name (#16578 by @sosukesuzuki)
There was a bug where block comments between the modifier and the name of a decorated property were being treated as trailing comments of the decorator. This behavior was not only unexpected but also lacked idempotency.
With this change, the position of the block comment between the modifier and the property name is preserved.Don't print an extra line break for arrow function with type parameter in assignment (#16586 by @sosukesuzuki)
There was a bug where an extra line was inserted when assigning a chained arrow function with type parameters to a variable if there was a line comment above it.
This change ensures that the extra line is no longer inserted.Support "Top-level await statements" (#16729 by @fisker)
Fix class heritage breaks even though it remains inside the line width (#16730 by @fisker)
Print declare before accessibility in class properties (#16731 by @fisker)
CSS
Resolve some types of overrun in CSS (#16570 by @seiyab)
Fix formatting of incomplete CSS value comments (#16583 by @sosukesuzuki, @fisker)
When formatting CSS value comments, the trailing / may be lost, resulting in an invalid comment.
This change ensures that value comments are not truncated.SCSS
Fix error thrown when formatting SCSS file (#16607 by @fisker)
Fix wrong trailing comma position after comment in SCSS (#16617 by @Ma-hawaj, @fisker)
HTML
Keep doctype in non-html files unchanged (#16765 by @fisker)
In Prettier v3, we print HTML5 doctype in lowercase, it's safe for HTML files, however users may use the html parser to format other files eg: XHTML files, lowercase the doctype will break XHTML documents.
Starting with Prettier 3.4, we'll only lowercase HTML5 doctype () when the file extension is .html or .htm, otherwise they will be untouched.Vue
Fix extra semicolon inserted in Vue event binding with non-ascii characters (#16733 by @fisker)
Angular
Support Angular 19 (#16862 by @fisker)
Angular 19 added support for typeof keyword in template expressions.Markdown
Remove excessive spaces after line prefixes for unordered lists in Markdown (#15526 by @TomasLudvik)
Fix incorrect wrap in sentence with linkReference (#16546 by @seiyab)
Preserve non-ASCII whitespaces at the end of the line and beginning of the next line (#16619 by @tats-u)
Prettier removes non-ASCII spaces at the end of the line and beginning of the next line. However, this behavior is not consistent with the CommonMark spec.Don't break a line a between Chinese or Japanese and others (#16691 by @tats-u)
Markdown documents are mainly converted to HTML or components of JavaScript-based frameworks. This means that paragraphs in Markdown are eventually processed by the browser according to CSS rules. This is because many Markdown converter preserve line breaks in paragraphs in input Markdown and HTML itself does not specify how browsers should handle line breaks in text in HTML.
According to CSS rules (CSS Text Module Level 3 or later), browsers should remove line breaks between Chinese/Japanese characters instead of replacing them with spaces. However, this rule has been ignored by WebKit-based or Webkit-derived browsers (Chrome, Safari, and so on) for long time.
For example, the following HTML paragraph:日本語 汉语 漢語
should be rendered as follows according to CSS rules and actually is rendered such by Firefox:
日本語汉语漢語However, Chrome and Safari render it as follows:
日本語 汉语 漢語This is why we should stop Prettier from line breaking between Chinese/Japanese characters. We decided to stop Prettier from forcing users to use a plugin for a Markdown converter that concatenates lines that start or end with Chinese/Japanese characters (remark-join-cjk-lines, for example).
Also, a line break between Chinese/Japanese and others are equivalent to a space according to before the commit suspending a concrete rule in CSS Text Module Level 3 by commenting it out fixing an issue on the CSS Working Group Editor Drafts. Firefox follows this rule. Therefore, all browsers render the following paragraph:<p> 日本語 English 汉语 韩国어 汉語 </p> <p> </p>as follows:
日本語 English 汉语 한국어 漢語However, Prettier has broken a line between Chinese/Japanese characters in Markdown for a long time, and between Chinese/Japanese and latin characters in some cases since 3.0.0. For example, the following Markdown paragraph:
日本語English汉语
English
漢語is formatted as follows if --prose-wrap is set to the other value than preserve in Prettier 3.x:
日本語English汉語English漢語However, the following HTML, which is generated by a Markdown-to-HTML converter based on the above Markdown:
日本語English汉語 English 漢語
is rendered as follows by all browsers:
日本語English汉語 English 漢語This is why we should stop Prettier from line breaking al so around Chinese/Japanese characters in Markdown. We are going to conform Prettier's behavior to this rule in a future version. After that, line breaks between Chinese/Japanese and others will be allowed again under certain rules.
One of the few exceptions is spaces and line breaks between Chinese/Japanese and Korean letters. The following Markdown paragraphs are equivalent even in the current Prettier version:
현재 韓國의 大統領은 尹錫悅이다.You get the former if you format the latter with --prose-wrap=always and a sufficiently long --print-width value or with --prose-wrap=never, and you get the latter if you format the former with --prose-wrap=always with a extremely short --print-width value. Therefore, we do not have to touch such spaces and line breaks.
Another exception is those between a Chinese/Japanese character and a meaningful symbol in Markdown like *,, [, and ]. For example, the following Markdown paragraph is equivalent even in the current Prettier version: ** Yarn ** のCLI経由でフォーマットするにはyarn prettier -w ` を実行してください。Tell regexp-util to generate regex compatible with u flag (#16816 by @tats-u)
CJK characters outside of BMP and Ideographic Variation Sequences (IVS; variation selectors dedicated for han/kanji), which consume 2 characters in JavaScript string, have not been treated as CJK. This is due to the fact that Prettier has not passed the appropriate flag "u" to the regexp-util package.
In the following example, “𠮷” (U+20BB7) is out of BMP, and “葛󠄀” is a combination of a han “葛” (U+845B) in BMP and an IVS U+E0100. The latter requires a font with the support of Adobe Japan-1 (e.g. Yu Gothic UI and Source Han Sans) to be rendered as a form different from that of the character without IVS (葛).API
Stop doc mutation in prettier.doc.printDocToString (#13315 by @fisker)
For performance reason, prettier.doc.printDocToString used to mutate .parts of the fill command during print. It was converted to a pure function to ensure output correctness.Make getPreferredQuote public (#16567 by @sosukesuzuki)
This change makes the internal getPreferredQuote function a part of the public API.
In languages like JavaScript, both single quotes and double quotes can be used for string literals. Prettier determines the quote to enclose a string literal based on the number of quotes within the string and the value of the singleQuote option. For more details, please refer to the Rationale page.
The getPreferredQuote function determines the appropriate quote to enclose a string literal and has the following interface:Here are some examples of how to use it:
Making this function public will benefit plugin developers. Since the function is relatively short, you can find more details in the implementation.
Fix loading ESM-style shared config file in Node.js 23 (#16857 by @sosukesuzuki)
In Prettier 3.3, attempting to load an ESM-style shared config file in Node.js 23 resulted in the following warnings, preventing the options from being loaded:
[warn] Ignored unknown option { __esModule: true }.
[warn] Ignored unknown option { default: { trailingComma: "es5", tabWidth: 4, singleQuote: true } }.
This issue was caused by a new module feature in Node.js 23, known as require(ESM). Prettier 3.4 resolves this problem, allowing the options to load correctly.
For more details, please see https://github.com/prettier/prettier/issues/16812.CLI
Ignore files in the Jujutsu directory (#16684 by @marcusirgens)
The Jujutsu VCS uses the .jj directory, similarly to how Git uses .git.
This change adds .jj to the list of directories which are silently ignored by prettier.Miscellaneous
Fix cursorOffset feature sometimes being catastrophically slow (#15709 by @ExplodingCabbage)
Original source Report a problem
Previously, Prettier's cursorOffset feature would be spectacularly slow in certain unfortunate circumstances (namely when the user's cursor was not contained within a leaf node of the AST, and the non-leaf node containing it was very large and being significantly reformatted by Prettier). As a consequence, if you used Prettier via an editor integration that used cursorOffset under the hood, your editor would sometimes inexplicably hang when you tried to format a file.
All examples of this phenomenon that we are aware of should now be fixed, but bug reports of any further pathological examples would be welcome. - Jun 1, 2024
- Parsed from source:Jun 1, 2024
- Detected by Releasebot:Dec 9, 2025
Prettier 3.3: New Flow features and a lot of bug fixes
A major release adds Flow feature support with component and hook declarations, plus big int enums and inexact tuple types. It also broadens type guards and improves JavaScript formatting, template handling, and TS type tweaks for cleaner, more accurate code output.
Highlights
Flow
declare namespace printing support (#16066 by @SamChou19815)
Input
declare namespace foo {
declare var bar: string;
}Prettier 3.2
// does not parsePrettier 3.3
declare namespace foo {
declare var bar: string;
}
Component syntax printing support (#16191 by @SamChou19815)
Input
component MyComponent(a: string, b: number) renders SomeComponent {
return ;
}
hook useMyHook(a: string) {
return useState(a);
}Prettier 3.2
// does not parsePrettier 3.3
component MyComponent(a: string, b: number) renders SomeComponent {
return ;
}
hook useMyHook(a: string) {
return useState(a);
}
Support big int Enums (#16268 by @gkz)
Adds support for big int Flow Enums.
Input
enum E {
A = 0n,
B = 1n,
}Prettier 3.2
// errorPrettier 3.3
enum E {
A = 0n,
B = 1n,
}
Support inexact tuple types (#16271 by @gkz)
Adds support for Flow's inexact tuple types.
- Input
type T = [number, ...];
// Prettier 3.2
type T = [number];// Prettier 3.3
type T = [number, ...];Support 'implies' type guard variant (#16272 by @gkz)
Adds support for Flow's implies type guard variant. Also updates the flow-parser dependency.
- Input
declare function f(x: mixed): implies x is T;
// Prettier 3.2
// error- Prettier 3.3
declare function f(x: mixed): implies x is T;
Other Changes
JavaScriptUnquote keys in import attributes (#15888 by @sosukesuzuki)
Input
import json from "./mod.json" with { "type": "json" };
// Prettier 3.2
import json from "./mod.json" with { "type": "json" };// Prettier 3.3
import json from "./mod.json" with { type: "json" };Fix unstable object print (#16058 by @fisker)
Input
a = { "\a": 1, "b": 2 }
// Prettier 3.2 (--quote-props consistent)
a = { "a": 1, "b": 2 };// Prettier 3.2 (--quote-props as-needed)
a = { "a": 1, b: 2 };// Prettier 3.3
a = { a: 1, b: 2 };Format embedded GQL in template literal statements (#16064 by @keithlayne)
Input
/* GraphQL */query foo { id };
// Prettier 3.2
/* GraphQL */query foo { id };// Prettier 3.3
/* GraphQL */query foo { id };Improve formatting of React useImperativeHandle hook (#16070 by @Jaswanth-Sriram-Veturi)
Input
useImperativeHandle(ref, () => {
/* Function body */
}, []);
// Prettier 3.2
useImperativeHandle(
ref,
() => {
/* Function body */
},
[]
);// Prettier 3.3
useImperativeHandle(ref, () => {
/* Function body */
}, []);Allow linebreaks in member expressions in template interpolations (#16116 by @bakkot)
When there is already a linebreak in a template interpolation, allow it to stay there even if it is a member expression. Note that (as of #15209) Prettier will not insert a linebreak inside an interpolation when one is not already present.Input
template with ${ very.very.very.very.very.very.very.very.very.very.long.chain };
// Prettier 3.2
template with ${very.very.very.very.very.very.very.very.very.very.long.chain};// Prettier 3.3
template with ${ very.very.very.very.very.very.very.very.very.very.long.chain };Fix dynamic import when the module source is a template string (#16267 by @fisker)
Input
const module = await import(data:text/javascript, console.log("RUN"););
// Prettier 3.2
const module = await (data:text/javascript, console.log("RUN"););// Prettier 3.3
TypeScript
const module = await import(data:text/javascript, console.log("RUN"););Add missing parentheses to TSInferType (#16031 by @fisker)
Input
type Foo = T extends (infer U extends number) | { a: infer U extends number } ? U : never;
// Prettier 3.2
type Foo = T extends infer U extends number | { a: infer U extends number } ? U : never;// Prettier 3.3
type Foo = T extends (infer U extends number) | { a: infer U extends number } ? U : never;Throw errors for duplicated accessibility modifiers (#16040 by @fisker, @auvred)
Input
class Foo {
public public bar() {}
};
// Prettier 3.2
class Foo {
public bar() {}
}// Prettier 3.3
SyntaxError: Accessibility modifier already seen.
(2:10)1 |
class Foo {2 | public public bar() {}
| ^^^^^^
3 |Respect --no-semi for readonly class field (#16133 by @sxzz)
Input
class A {
readonly [expr] = true
}
// Prettier 3.2
class A {
field;
readonly [expr] = true
}// Prettier 3.3
class A {
field
readonly [expr] = true
}Add necessary parentheses to yield expressions (#16194 by @kirkwaiblinger)
Add parentheses around yield expressions if parent is an angle-bracket type assertion.Input
function* g() {
const y = (yield x);
}
// Prettier 3.2
function* g() {
const y = yield x;
}// Prettier 3.3
function* g() {
const y = (yield x);
}Markdown
- Improve wrapping for code block in markdown and jsx in mdx (#15993 by @seiyab)
img { filter: drop-shadow(2px 2px 0 hsl(300deg 100% 50%)) drop-shadow( -2px -2px 0 hsl(210deg 100% 50%) ) drop-shadow(2px 2px 0 hsl(120deg 100% 50%)) drop-shadow( -2px -2px 0 hsl(30deg 100% 50%) ); }img { filter: drop-shadow(2px 2px 0 hsl(300deg 100% 50%)) drop-shadow( -2px -2px 0 hsl(210deg 100% 50%) ) drop-shadow(2px 2px 0 hsl(120deg 100% 50%)) drop-shadow( -2px -2px 0 hsl(30deg 100% 50%) ); }
APIimg { filter: drop-shadow(2px 2px 0 hsl(300deg 100% 50%)) drop-shadow(-2px -2px 0 hsl(210deg 100% 50%)) drop-shadow(2px 2px 0 hsl(120deg 100% 50%)) drop-shadow(-2px -2px 0 hsl(30deg 100% 50%)); }- Add support for package.yaml config (#16157 by @danielbayley)
Enable support for reading prettier configuration from package.yaml.
package.yaml
prettier:
Original source Report a problem
semi: false
singleQuote: true - Jan 12, 2024
- Parsed from source:Jan 12, 2024
- Detected by Releasebot:Dec 9, 2025
Prettier 3.2: Support JSONC and Angular’s ICU expression
Prettier adds a jsonc parser and Angular ICU expression support along with many fixes. The update tightens jsonc behavior and improves template and chaining formatting for more predictable results.
Highlights
JSON
New jsonc parser added (#15831 by @fisker)
Previously, we infer the parser of .jsonc files to be json, but if we want keep the trailing comma, we'll have to use a hacky workaround config {parser: "json5", quoteProps: "preserve", singleQuote: false}.The new added jsonc parser:
- Always quote the object keys.
- Wrap strings with double quotes.
- Of course, respect the trailingComma option.
Angular
Support formatting for Angular ICU expression (#15777 by @sosukesuzuki)
Support two kinds of Angular ICU expressions: plural and select.Other Changes
JavaScriptAvoid introducing linebreaks in template interpolations (#15209 by @bakkot)
In a template string likethis is a long message which contains an interpolation: ${format(data)}; avoid adding a linebreak when formatting the expression unless one is already present or it's unavoidable due to e.g. a nested function. Previously a linebreak could be introduced whenever some interpolation in the template was sufficiently "not simple". Now it will instead be left alone. If a linebreak is already present within the ${...}, format as normal.Fix non-idempotent formatting of method chain with empty line (#15522 by @seiyab)
Fix formatting of ternary in function call (#15677 by @fisker)
Fix inconsistencies for optional-chaining (#15806 by @fisker)
Only happens when using typescript, meriyah, or other ESTree parsers except babel.Fix comments in if (#15826 by @fisker)
- Improve conditional type alias layout (#15811 by @seiyab)
- Fix formatting of prettier-ignored unclosed elements (#15748 by @fisker)
Fixes scenarios where an input handlebars file containing literal segments would be reformatted to unwrap the literal segments, causing syntax errors in the resulting output.
Fix prettier-ignored angular control flow block (#15827 by @fisker)
Avoid adding colon for track in 3rd expression of for blocks (#15887 by @sosukesuzuki)
- Preserve path literal segments (#15605 by @maxpowa)
Fixes scenarios where an input handlebars file containing literal segments would be reformatted to unwrap the literal segments, causing syntax errors in the resulting output.
- Improve GraphQL union types formatting (#15870 by @ArchitGajjar)
Support absolute path as plugin in config file (#15666 by @fisker)
Fix getFileInfo and getSupportInfo type definitions (#15854 by @auvred)
- Fix false claim in docs that cursorOffset is incompatible with rangeStart/rangeEnd (#15750 by @ExplodingCabbage)
The cursorOffset option has in fact been compatible with rangeStart/rangeEnd for over 5 years, thanks to work by @ds300. However, Prettier's documentation (including the CLI --help text) continued to claim otherwise, falsely. The documentation is now fixed.
- Nov 13, 2023
- Parsed from source:Nov 13, 2023
- Detected by Releasebot:Dec 9, 2025
Prettier 3.1: New experimental ternaries formatting and Angular control flow syntax!
This release brings indentation for nested ternaries and a new experimental-ternaries flag offering a curious, readable format for complex conditionals. It adds Angular 17 control flow support and updates Babel 7.23.0 syntax, plus a set of quality fixes.
This release adds indentation back to nested ternaries along with a new --experimental-ternaries flag to try a more novel "curious ternary" format that scales better to deeply nested conditionals. We are keen for your feedback on the experimental format before it rolls out as the default behavior later this year!
We have also added support for the control flow syntax in Angular v17. For details on the syntax, please read the official Angular release post.
If you appreciate Prettier and would like to support our work, please consider sponsoring us directly via our OpenCollective or by sponsoring the projects we depend on, such as typescript-eslint, remark, and Babel. Thank you for your continued support!
Highlights
JavaScript
Add indentation back to nested ternaries (#9559 by @rattrayalex)
New Experimental Ternary Formatting: A Curious Case of the Ternaries (#13183 by @rattrayalex)
This is implemented behind a --experimental-ternaries flag.
We move the ? in multiline ternaries to the end of the first line instead of the start of the second, along with several related changes.
While it might look weird at first, beta-testing shows that after a few hours of use, developers find it makes nested ternaries much more readable and useful.
This PR resolves one of our a highly-upvoted issue without the problems its proposed solution would reintroduce.
Please see A curious case of the ternaries for more details.
Example
// "Questioning" ternaries for simple ternaries:
const content = children && !isEmptyChildren(children) ? render(children) : renderDefaultChildren();
// "Case-style" ternaries for chained ternaries:
const message = i % 3 === 0 && i % 5 === 0 ? "fizzbuzz" : i % 3 === 0 ? "fizz" : i % 5 === 0 ? "buzz" : String(i);
// Smoothly transitions between "case-style" and "questioning" when things get complicated:
const reactRouterResult = children && !isEmptyChildren(children) ? children : props.match ? component ? React.createElement(component, props) : render ? render(props) : null : null;
Support new syntaxes supported by Babel 7.23.0 (#15485, #15486, #15487, #15488 by @sosukesuzuki)
We support new JS syntax supported by Babel 7.23.0 !
Source Phase Imports
Please see https://github.com/tc39/proposal-source-phase-imports for more details.
import source x from "mod";
Deferred Import Evaluation
Please see https://github.com/tc39/proposal-defer-import-eval for more details.
import defer * as ns from "mod";
Optional Chaining Assignments
Please see https://github.com/tc39/proposal-optional-chaining-assignment for more details.
maybeObj?.prop1 = value;
Angular
- Support Angular control flow (#15606 by @DingWeizhe, @fisker)
- Added support for built-in control flow in Angular 17. Please give us feedback if you find any bugs.
- For more details about control flow, please check this article on the official blog.
- https://blog.angular.io/introducing-angular-v17-4d7033312e4b
Other Changes
JavaScript- Fix comment between parentheses and function body (#15326 by @fisker)
- Disambiguate unary expressions on left hand side of instanceof and in (#15468 by @lucacasonato)
- Parentheses are now added around unary expression on the left hand side of instanceof and in expressions, to disambiguate the unary on the left hand side with a unary applying to the entire binary expression.
- This helps catch a common mistake where a user intends to write !("x" in y) but instead writes !"x" in y, which is really parsed as the nonsensical (!"x") in y.
- Fix name case of selectors in styled components interpolation (#15472 by @lucasols)
- Consistently format strings containing escapes (#15525 by @sosukesuzuki)
- Improve formatting for assignment its left can break (#15547 by @sosukesuzuki)
- Support embedded formatting in template literals annotated with as const (#15408 by @sosukesuzuki)
- Fix printing comment for the last operand of union types (#15409 by @sosukesuzuki)
- Keep required parenthesis around some specific keyword like identifiers in expression statement of satisfies / as expression (#15514 by @seiyab)
- Support as and satisfies expressions for Flow (#15130 by @gkz)
- Support type arguments on jsx opening elements for Flow (#15429 by @SamChou19815)
- Support type arguments after typeof (#15466 by @sosukesuzuki)
- Do not split call of scss function with leading dash (#15370 by @auvred)
- Fix formatting of menu and marquee elements (#15334 by @fisker)
- Encoding < and > in markdown urls (#15400 by @vivekjoshi556)
- Don't split lines between Japanese kana & COMBINING KATAKANA-HIRAGANA (SEMI-)VOICED SOUND MARK (#15411 by @tats-u)
- Accept URL in prettier.{resolveConfig,resolveConfigFile,getFileInfo}() (#15332, #15354, #15360, #15364 by @fisker)
- Process files only supported by plugins (#15433 by @sosukesuzuki)
- Show (unchanged) keyword for accessibility in CLI --write (#15467 by @ADTC)
- Fix error when formatting file names contains special characters (#15597 by @fisker)
- Nov 13, 2023
- Parsed from source:Nov 13, 2023
- Detected by Releasebot:Dec 9, 2025
Prettier 3.1.0: A curious case of the ternaries
Ternary formatting gets a new curious style in v3.1.0, offering a readable, case-style approach for nested ternaries. The feature ships behind an experimental --experimental-ternaries flag, inviting developers to try and share feedback while the team weighs it for mainstream use.
Introduction
Ternary formatting has always been a challenge, and we're finally addressing it in v3.1.0 with the introduction of a novel formatting style.
Read on for our journey and the motivation behind this change, along with early developer feedback and an overview of the "curious ternaries" style.
Please give the --experimental-ternaries option a try and let us know what you think!
For a quick tl;dr, see the release post.Formatting nested ternaries nicely in a wide variety of scenarios is a surprisingly tricky challenge.
Developers have long found them so confusing to read that they end up just refactoring their code to an ugly series of if-else statements, often with a let declaration, an iife, or a separate function entirely.
According to beta testers, the new formatting style we've developed can take some getting used to, but ultimately allows ternaries to be practically used as a concise form of if-else-expressions in modern codebases.Historical background
Prettier's original, naïve approach 6 just add indentation to each level of a nested ternary 6 worked fine in simple cases, but obviously doesn't scale to long chains of nested ternaries and had other problems.
So in 2018, we replaced that with flat ternaries, which seemed like a good idea at the time, but was not received well 6 the issue asking it to be reverted had well over 500 upvotes.
While we did ultimately revert back to indented ternaries, we wanted to find a better way.
Over the last few years, we explored and experimented with many, many possible solutions which would be as readable as indented ternaries in common cases, but also scale to work well in a wider variety of situations.Challenging criteria
Ideally, we'd find one scheme that would meet our criteria:
- In all cases, it should be easy to follow "what's the if", "what's the then", and "what's the else" 6 and what they map to.
- The code should fluidly flow from a single ternary, to a chain of 2, to a long chain of simple cases, to something more complex with a few nested conditions. (Most alternatives we explored failed this test).
- The syntax in JSX, TypeScript conditional expressions (which cannot be expressed with if), and normal JS should all look and feel the same.
- It should scale to nested ternary chains of arbitrary length (imagine a TypeScript conditional type with dozens of alternative cases).
Indented ternaries clearly failed (4), arguably (1), and even (3) 6 we have almost always printed JSX ternaries in a flat-but-readable format that unfortunately felt unnatural outside of JSX.
Many people in the community were excited about a "case-style", drawing inspiration from the match syntax from languages like Rust or OCaml, but it did not meet (2) and other goals.
- It should scale to nested ternary chains of arbitrary length (imagine a TypeScript conditional type with dozens of alternative cases).
A surprising solution
The good news is that we found a formatting algorithm that met our criteria. The bad news is that it's novel, and thus unfamiliar to most developers.
In beta testing this feature, we found developers were quite skeptical when they first saw it:
"I'm not convinced the new version is simpler to read here."
But then, after using it for a bit, they didn't want to go back:
"I'm liking the ternaries! I think it makes sense to have them formatted like this. I also got used to them quite quickly as well.
I agree with this, it takes a very short time to get used to it."
Another developer had this to say:
My first hour with the rule on, it felt a little odd. But by hour two, I’d used it a few times to solve problems that otherwise would have been ugly refactors to if statements. I’m not going back.
I used to hate nested ternaries, but I also hate restructuring a nice line of code into if-else statements. The new rule adds an understandable, linear if-else, if-else expression to the language and is much nicer than multiple ternaries as nested branches.
So we felt we had a winning formula, but we knew it could be a jarring introduction to the community.
As a result, we decided to put this new formatting behind a temporary --experimental-ternaries option for a few months, and in the meantime go ahead and ship what the community has been clamoring for: indented ternaries.Styling Overview
So what does this new style look like, anyway?
Here's a quick, contrived example to show the thinking behind "curious" ternaries:const animalName = pet.canBark() ? pet.isScary() ? 'wolf' : 'dog' : pet.canMeow() ? 'cat' : 'probably a bunny';- Every line that ends with a question mark is an "if".
- If you see foo ?, it's like asking a question about foo – "if foo? then, …".
- Every line that starts with a : is an "else".
- If you see : foo that means, "else, foo".
- If you see : foo ? that means "else, if foo?".
- Every line without : or ? is a "then".
- If you just see foo, that means, "then foo".
And here's the code rewritten to demonstrate "case-style" ternaries:
const animalName = pet.isScary() ? 'wolf' : pet.canBark() ? 'dog' : pet.canMeow() ? 'cat' : 'probably a bunny';You can see this is a nice concise way to get something approaching match-style syntax in JavaScript, with just the humble ternary operator (albeit missing several features).
Our new formatting is a fluid blend of "curious" ternaries (where the question mark is always at the end of the line), and "case-style" ternaries, where the question mark is in the middle of the line.
For example:const animalName = pet.canSqueak() ? 'mouse' : pet.canBark() ? pet.isScary() ? 'wolf' : 'dog' : pet.canMeow() ? 'cat' : pet.canSqueak() ? 'mouse' : 'probably a bunny';Give us your feedback!
Original source Report a problem
We hope you like the more readable new default, and we really hope you give the new --experimental-ternaries option a try for a few weeks and let us know what you think.
Please give us feedback via Google Forms: https://forms.gle/vwEuboCobTVhEkt66
This is the end. You've seen all the release notes in this feed!