| | |

Prettier 10 ๐ŸŽจ Parser Inference โ€” How file extensions map to parsers

โฑ๏ธ Estimated read: 10 min | |

Prettier does not require a parser option in most cases. When it formats a file, it looks at the file’s extension and infers which parser to use. A .ts file uses the TypeScript parser. A .css file uses the CSS parser. A .md file uses the Markdown parser. The parser option exists as an override for the cases where the extension is ambiguous, the file is passed through stdin, or the content does not match the extension. But placing parser at the top level of a configuration file disables the inference entirely and forces every file through one parser, which is almost always a mistake.

This chapter covers the inference mechanism, the extension-to-parser mapping for the major languages, the cases where inference fails and an explicit parser is required, and the rule that parser belongs inside overrides, never at the top level.

Key point: Prettier infers the parser from the file extension by default. A top-level parser setting disables that inference and forces every file to use the specified parser, which breaks formatting for every other file type in the project.


Why parser inference exists

The configuration problem. A project contains JavaScript, TypeScript, CSS, JSON, Markdown, and YAML files. Each language needs a different parser. If every file required an explicit parser option, the configuration would need an overrides entry for every file type, and adding a new file type would require a configuration change. The extension-based inference removes that burden: the file name carries the information, and Prettier reads it .

The API problem. The prettier.format() function receives source text, not a file path. Without a file path, Prettier has no way to infer the parser. The filepath option provides the path, and Prettier uses the extension to select the parser. The --stdin-filepath CLI flag does the same for piped input . A file that is passed through stdin without a filepath must specify the parser explicitly, because there is no extension to inspect.

The ambiguity problem. Some extensions are ambiguous. A .html file could be standard HTML, an Angular template, or a Lightning Web Component. A .json file could be plain JSON, JSON with Comments (JSONC), or JSON5. Prettier maps the extension to a default parser, and the overrides mechanism handles the cases where the default is wrong for a specific file pattern.


a. The extension-to-parser mapping

Prettier’s built-in parsers map to extensions through the language definitions in its support information. The getSupportInfo() API returns the full list, including the extensions and filenames for each language . The major mappings are:

ExtensionParserLanguage
.js, .mjs, .cjsbabelJavaScript
.jsxbabelJSX
.ts, .mts, .ctstypescriptTypeScript
.tsxtypescriptTSX
.jsonjsonJSON
.jsonc, .json5json or json5JSON variants
.csscssCSS
.scssscssSCSS
.lesslessLess
.htmlhtmlHTML
.vuevueVue SFC
.md, .markdownmarkdownMarkdown
.mdxmdxMDX
.yaml, .ymlyamlYAML
.graphql, .gqlgraphqlGraphQL

The mapping is not exhaustive. Prettier also recognizes well-known filenames like package.json, tsconfig.json, and .prettierrc as JSON, and .editorconfig as INI. The filenames field in the support information covers these cases .


b. The top-level parser mistake

The parser option is documented as an override for the rare case where the extension is not sufficient. The documentation is explicit: do not put parser at the top level of the configuration. A top-level parser: "babel" forces every fileโ€”including CSS, JSON, and Markdownโ€”to be parsed as JavaScript. The CSS file fails to parse, the JSON file fails to parse, and the Markdown file fails to parse. The error messages are confusing because they point at syntax that is valid in its own language but invalid in JavaScript .

The correct placement is inside an overrides entry, where the files pattern scopes the parser to the files it applies to.

{
  "overrides": [
    {
      "files": "*.component.html",
      "options": {
        "parser": "angular"
      }
    }
  ]
}

The *.component.html pattern selects Angular component templates, and the parser: "angular" tells Prettier to use the Angular parser for those files instead of the default HTML parser. Every other file in the project continues to use extension-based inference.


c. When inference fails

Inference fails in three situations, and each has a different remedy.

Stdin without a filepath. Piping a file into Prettier without specifying the file path leaves Prettier with no extension to inspect. The --stdin-filepath flag provides the path, and inference works normally. Without the flag, the --parser flag is required.

cat foo.css | prettier --stdin-filepath foo.css

A non-standard extension. A file with an extension that Prettier does not recognize, such as .tpl or .myext, has no default parser. The overrides mechanism maps the extension to a parser.

An extension with multiple possible parsers. The .html extension is the most common case. Prettier defaults to the standard HTML parser, but Angular templates and Lightning Web Components use different parsers. The overrides mechanism selects the correct parser based on the file path or a naming convention like *.component.html.

The getFileInfo() API is what editor extensions use to determine whether a file needs formatting and which parser it would use. It returns inferredParser: string | null, where null means the file is ignored or the parser cannot be inferred. The editor can then fall back to an explicit parser or skip formatting .


Complete Example Session

// ============================================
// PART 1: THE API INFERENCE
// ============================================
await prettier.format("const x = 1", { filepath: "foo.js" })
// Prettier infers the babel parser from .js.
// ============================================
// PART 2: THE API WITHOUT A FILEPATH
// ============================================
await prettier.format("const x = 1", { parser: "babel" })
// No filepath, so the parser must be specified.
# ============================================
# PART 3: THE STDIN FILEPATH
# ============================================
cat foo.css | prettier --stdin-filepath foo.css
# The CSS parser is inferred from the extension.
# ============================================
# PART 4: THE STDIN WITHOUT FILEPATH
# ============================================
cat foo.css | prettier --parser css
# The parser must be specified explicitly.
// ============================================
// PART 5: THE TOP-LEVEL MISTAKE
// ============================================
{
  "parser": "babel"
}
// Every file is parsed as JavaScript.
// CSS, JSON, and Markdown fail.
// ============================================
// PART 6: THE CORRECT OVERRIDE
// ============================================
{
  "overrides": [
    {
      "files": "*.component.html",
      "options": { "parser": "angular" }
    }
  ]
}
// Only Angular templates use the Angular parser.
// ============================================
// PART 7: THE MULTIPLE OVERRIDES
// ============================================
{
  "overrides": [
    { "files": "*.component.html", "options": { "parser": "angular" } },
    { "files": "*.jsonc", "options": { "parser": "json" } }
  ]
}
// Each override scopes its parser to a file pattern.
// ============================================
// PART 8: THE GETFILEINFO API
// ============================================
const info = await prettier.getFileInfo("foo.css")
// { ignored: false, inferredParser: "css" }
// ============================================
// PART 9: THE IGNORED FILE
// ============================================
const info = await prettier.getFileInfo("node_modules/foo.js")
// { ignored: true, inferredParser: null }
// ============================================
// PART 10: THE SUPPORT INFO
// ============================================
const info = await prettier.getSupportInfo()
// info.languages contains the extensions and filenames
// for every supported language.

The ten parts covered the API inference, the API without a filepath, the stdin filepath, the stdin without a filepath, the top-level mistake, the correct override, multiple overrides, the getFileInfo API, the ignored file, and the support info.


Quick Reference

Inference mechanisms

ContextInference source
CLI file argumentFile extension
CLI stdin--stdin-filepath
API format()filepath option
API without filepathparser option required

Extension mapping (selected)

ExtensionParser
.jsbabel
.tstypescript
.jsxbabel
.tsxtypescript
.csscss
.scssscss
.htmlhtml
.vuevue
.mdmarkdown
.jsonjson
.yamlyaml

Parser placement

LocationEffect
Top levelDisables inference, forces one parser for all files
overrides[].options.parserScoped to the files pattern
CLI --parserForces the parser for the current invocation

API functions

FunctionPurpose
format()Format text; infer from filepath
getFileInfo()Return ignored and inferredParser
getSupportInfo()Return languages, extensions, parsers

Best Practices

โœ… Do This:

// Use overrides for non-standard extensions
{
  "overrides": [
    { "files": "*.component.html", "options": { "parser": "angular" } }
  ]
}                                                            // โœ…
# Provide the filepath for stdin
cat foo.css | prettier --stdin-filepath foo.css              // โœ…
// Provide the filepath for the API
prettier.format(text, { filepath: "foo.ts" })                // โœ…

โŒ Don’t Do This:

// Put parser at the top level
{ "parser": "babel" }                                        // โŒ
# Pipe without a filepath or parser
cat foo.css | prettier                                       // โŒ (no parser)
// Use parser for a file type that has a default
{ "parser": "typescript" }  // unnecessary for .ts files      // โŒ

Common Pitfalls

PitfallWhy It HappensFix
CSS/JSON files fail to parseTop-level parser: "babel"Move the parser into an overrides entry
Stdin formatting failsNo filepath and no parserAdd --stdin-filepath or --parser
Angular template formatted as HTMLDefault .html parser is usedAdd an override for *.component.html
Editor does not format a filegetFileInfo returns nullCheck the extension or add an override
Unknown extension is skippedNo parser inferredAdd an override mapping the extension

Real-World Examples

1. API with filepath

prettier.format(text, { filepath: "foo.ts" })

2. API with parser

prettier.format(text, { parser: "typescript" })

3. Stdin with filepath

cat foo.css | prettier --stdin-filepath foo.css

4. Stdin with parser

cat foo.css | prettier --parser css

5. Top-level mistake

{ "parser": "babel" }

6. Correct override

{ "overrides": [{ "files": "*.component.html", "options": { "parser": "angular" } }] }

7. Multiple overrides

{ "overrides": [{ "files": "*.jsonc", "options": { "parser": "json" } }] }

8. getFileInfo

const info = await prettier.getFileInfo("foo.css")

9. Ignored file

const info = await prettier.getFileInfo("node_modules/foo.js")

10. Support info

const info = await prettier.getSupportInfo()

Visual

Inference flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  FILE EXTENSION                                              โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ”œโ”€โ”€ .ts โ”€โ”€โ–บ typescript parser                          โ”‚
โ”‚       โ”œโ”€โ”€ .css โ”€โ”€โ–บ css parser                                โ”‚
โ”‚       โ”œโ”€โ”€ .md โ”€โ”€โ–บ markdown parser                            โ”‚
โ”‚       โ””โ”€โ”€ unknown โ”€โ”€โ–บ no parser inferred                     โ”‚
โ”‚                                                              โ”‚
โ”‚  No explicit parser option is needed.                        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The top-level mistake

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  { "parser": "babel" }                                       โ”‚
โ”‚                                                              โ”‚
โ”‚  foo.ts โ”€โ”€โ–บ babel parser โ”€โ”€โ–บ TypeScript syntax fails         โ”‚
โ”‚  foo.css โ”€โ”€โ–บ babel parser โ”€โ”€โ–บ CSS syntax fails               โ”‚
โ”‚  foo.md โ”€โ”€โ–บ babel parser โ”€โ”€โ–บ Markdown syntax fails           โ”‚
โ”‚                                                              โ”‚
โ”‚  One parser forced on every file.                            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The override

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  {                                                           โ”‚
โ”‚    "overrides": [                                            โ”‚
โ”‚      {                                                       โ”‚
โ”‚        "files": "*.component.html",                          โ”‚
โ”‚        "options": { "parser": "angular" }                    โ”‚
โ”‚      }                                                       โ”‚
โ”‚    ]                                                         โ”‚
โ”‚  }                                                           โ”‚
โ”‚                                                              โ”‚
โ”‚  Only *.component.html uses the angular parser.              โ”‚
โ”‚  Every other file uses extension-based inference.            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Stdin

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  cat foo.css | prettier --stdin-filepath foo.css             โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ””โ”€โ”€ filepath provides the .css extension               โ”‚
โ”‚             โ””โ”€โ”€ css parser inferred                          โ”‚
โ”‚                                                              โ”‚
โ”‚  cat foo.css | prettier --parser css                         โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ””โ”€โ”€ parser specified explicitly                        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Default behaviorInfer parser from file extension
CLI stdin--stdin-filepath for inference, --parser for explicit
API stdinfilepath option for inference, parser for explicit
Override locationoverrides[].options.parser
Top-level parserDisables inference, breaks other file types
Ambiguous extensionsHandled with overrides
getFileInfoReturns inferredParser or null
getSupportInfoReturns the full extension mapping

Key takeaways:

  • Prettier infers the parser from the file extension by default. A .ts file uses the TypeScript parser, a .css file uses the CSS parser, and a .md file uses the Markdown parser. No parser option is needed for files with standard extensions .
  • A top-level parser setting disables inference. The documentation states explicitly that parser should never be placed at the top level of a configuration file. It forces every file through one parser, which breaks CSS, JSON, Markdown, and every other file type that is not the specified language .
  • The parser option belongs inside overrides. When an extension is ambiguous or non-standard, an overrides entry with a files pattern scopes the parser to the files it applies to. The rest of the project continues to use inference .
  • Stdin requires a filepath or a parser. A piped file has no extension unless --stdin-filepath provides one. Without it, the --parser flag is required. The API behaves the same way with the filepath option .
  • getFileInfo() is how editors decide whether and how to format. It returns ignored and inferredParser. A null parser means the file is ignored or the extension is not recognized. The editor can then fall back to an explicit parser or skip formatting .

Remember: Parser inference is the default because the file extension is the most reliable signal of the language. The parser option is an override for the cases where the extension is not enough: stdin without a path, a non-standard extension, or an extension that maps to multiple parsers. Put the override inside overrides, never at the top level. A top-level parser is not a configuration shortcut; it is a way to break every file type that is not the one you specified.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!