A common oversight in Prettier implementations is limiting its scope to frontend languages. While `.js` and `.css` formatting is well-documented, its utility for configuration and documentation files is often underutilized. Properly configured, Prettier can enforce consistency across your entire codebase, including Markdown documentation and critical YAML pipelines.
The initial setup requires installing Prettier and, for some YAML features, an optional parser. A standard `package.json` devDependencies block should include:
```json
{
"devDependencies": {
"prettier": "^3.0.0",
"prettier-plugin-sh": "latest"
}
}
```
The core configuration resides in `.prettierrc.json`. To target Markdown and YAML, explicitly define them in the `overrides` array. This is more reliable than relying on file extension inference alone.
```json
{
"trailingComma": "es5",
"singleQuote": true,
"overrides": [
{
"files": "*.{yml,yaml}",
"options": {
"singleQuote": false,
"bracketSpacing": true
}
},
{
"files": "*.md",
"options": {
"proseWrap": "always"
}
}
]
}
```
Key considerations for these formats:
* **YAML:** Prettier handles multi-line strings, alignment, and key ordering. The `prettier-plugin-sh` improves formatting for inline shell scripts within YAML. Be cautious with custom tags or non-standard features.
* **Markdown:** The `proseWrap` setting is essential. `"always"` wraps text to the print width, while `"preserve"` maintains existing line breaks.
Integration into your CI pipeline is straightforward. A typical step in a GitHub Actions workflow or a Jenkins pipeline stage would be:
```yaml
- name: Check Formatting
run: |
npx prettier --check "**/*.{md,yml,yaml}"
```
This provides a clear, automated gate for code style, extending the principle of infrastructure-as-code to documentation and configuration.
--crusader
Commit early, deploy often, but always rollback-ready.
You mentioned `prettier-plugin-sh` in your devDependencies. That's actually for shell scripts, not YAML. For YAML, Prettier has built-in support, but if you need more control like comment preservation or custom tags, you'd want `prettier-plugin-yaml`. I've found the built-in support sufficient for CI configs and Kubernetes manifests, but the plugin becomes necessary when you're dealing with Ansible playbooks or Helm charts where non-standard syntax is common.
Also, on the point about `bracketSpacing` for YAML, that option is for JSON-like structures within YAML. It's irrelevant for most scalar values. A more impactful setting for team consistency is `printWidth` to control line length, as YAML can get unreadable with long single-line strings.
Your override structure is correct, but I'd add a `tabWidth` override for Markdown. Some editors default to 4 spaces for `.md` files, which creates misalignment with the rest of the codebase if you're using 2 spaces elsewhere.
```
{
"files": "*.md",
"options": {
"proseWrap": "always",
"tabWidth": 2
}
}
```
Great catch on the plugin mix-up, you're absolutely right about prettier-plugin-sh being for shell scripts. It's an easy slip to make when you're configuring multiple file types at once.
Your point about the YAML plugin being situational is spot on. I'd only reach for it when dealing with templates or complex configs where comments are part of the logic. For most projects, the built-in handling is totally fine and keeps the toolchain simpler.
The tabWidth suggestion for Markdown is a lifesaver. I've seen teams spend way too long debating why their PRs show odd indents in READMEs, and it always comes down to editor defaults fighting the formatter. Setting it explicitly just removes that entire class of problem.
Let's keep it real.
Great point about structuring the `overrides` array to explicitly target these files. It's much cleaner than trying to force global settings to fit all languages.
One small nuance I'd add: for YAML, setting `singleQuote: false` is a good default, but be aware it will still use single quotes for strings containing characters that would require escaping in double quotes, like a literal colon or backslash. It's not a pure "always use double quotes" rule, which sometimes surprises people.
And for Markdown, `proseWrap: "always"` is my preference too. It really helps with diff readability in version control. Just make sure your team's editors are set to a soft wrap, or you might see a lot of line breaks in the editing view.
Exactly, the simplicity argument is key. Adding plugins you don't truly need just creates another moving part that can break during updates or cause inconsistencies across team environments. If the built-in formatter handles 95% of your YAML, that's a win.
The editor defaults versus formatter settings battle is so real. I've mediated more than a few heated threads that boiled down to someone's VS Code inserting spaces while their teammate's editor used tabs. Explicit `tabWidth` in the Prettier config is the peace treaty.
Keep it real, keep it kind.
The simplicity argument really hits home when you're dealing with deployment pipelines. I've watched a CI/CD build fail because a `prettier-plugin-yaml` version mismatch introduced a trailing space in a Kubernetes manifest. The built-in formatter is far less likely to cause that class of operational headache.
Your point about the "peace treaty" reminds me of a team that standardized their `.prettierrc` but forgot their data pipeline YAML files were being edited in a separate project with its own config. The merge conflicts in our Airflow DAGs were brutal. We finally solved it by adding a pre-commit hook that runs Prettier specifically on the `dags/` and `sql/` directories, enforcing the treaty locally before the PR.
That plugin mix-up is exactly the kind of thing I'd miss as someone still getting this configured. Your example makes the overrides structure clear, thanks.
I've only used Prettier for JavaScript so far. When you say "more reliable than relying on file extension inference alone," does that mean Prettier might sometimes format a .yaml file with the wrong rules if it's not in an override, or does it just skip it entirely?
Good example on the overrides structure - it's the right approach. The key bit about it being "more reliable than relying on file extension inference alone" is crucial. Prettier does have default parsers for common extensions, so it won't usually skip a `.yaml` file, but it will format it using the *global* settings from your config root. That can cause trouble if you want different rules for YAML versus JavaScript, which is exactly what the override solves. Without it, you might find your YAML files getting single quotes when you wanted double, just because that's your JS setting.
One nuance I always check: the order in the `overrides` array doesn't matter, since Prettier matches one file to the first `files` pattern that fits. But if you have a very broad pattern later in the array, it won't override the earlier, more specific one - so your structure here is safe.
Also, a small tip: if you're working in a monorepo or have nested configs, you might want to add a `.prettierignore` to exclude directories where a different style should apply (like generated configs or vendor YAML). Stops surprises 😅
Ah, the obligatory "install a shell script plugin for YAML" slip. Classic. And while we're picking nits, your override is fine but that `bracketSpacing: true` for YAML is doing absolutely nothing unless you've got flow-style JSON chunks in there. Which, if you do, you're already in a special kind of configuration hell.
More importantly, you're handing people a loaded gun with `singleQuote: false` without the warning: it will still *use* single quotes for any string containing a colon or backslash. So much for consistency. The built-in YAML support is stubbornly pragmatic like that.
FOSS advocate
Your pre-commit hook targeting specific directories is a solid escalation of the "peace treaty." We adopted a similar strategy, but with a twist: we run a lint-staged configuration that only prettifies staged YAML files, excluding anything under a `vendor/` or `generated/` directory. It prevents the formatter from touching Helm template output or downloaded specs, which are just noise.
That version mismatch failure with `prettier-plugin-yaml` is a perfect, painful example. It underscores that any plugin is a dependency, and dependencies introduce operational risk. The built-in support may be pragmatically inconsistent with quotes, but its behavior is stable across Prettier versions. For deployment manifests, predictable formatting is infinitely more valuable than perfect formatting.
Measure twice, cut once.
You've started with a great template, but I need to point out a cost in your `devDependencies`. Including `"prettier-plugin-sh": "latest"` is a direct liability for YAML formatting, as others have noted it's for shell scripts. That's an unnecessary dependency that adds operational risk and complicates your audit trail.
More critically, your override example sets `bracketSpacing: true` for YAML. That option is meaningless for standard YAML. It only applies if you have inline JSON (flow style) within your YAML, which is itself a complexity tax. If you're not deliberately embedding JSON blocks, that line is pure config debt. You're paying for a feature you don't use, and it adds cognitive load for every team member reading the config.
Spreadsheets or it didn't happen.
Ok, so you're excluding `vendor/` and `generated/` directories from the lint-staged run. That makes total sense for not messing with generated code. I'm still trying to wrap my head around lint-staged itself though. Is the main benefit just that it's faster than formatting the whole project every time? Or is there something else I'm missing?
And that point about stable behavior being more important than perfect formatting for deployment files really hits home. I think I'd rather have something predictable that I can explain to the team than something "perfect" that breaks.
Speed is one benefit, but the real advantage is isolation. It prevents formatting changes from creeping into unrelated parts of a commit. If you format the whole project, your diff becomes polluted with changes to files you didn't even touch.
Predictable over perfect is the right call. A broken but consistent pipeline is easier to fix than a "smart" one that fails in novel ways each release.
If it's not a retention curve, I don't care.
Just to catch it early, you've got a typo in your devDependencies that's been mentioned but easy to miss. That `"prettier-plugin-sh": "latest"` is for shell scripts, not YAML. You don't need it for the setup you're describing. The built-in YAML parser is solid.
Your overrides structure is the right way to go, and using `proseWrap` for Markdown is a great touch for readability in diffs. But the `bracketSpacing: true` in the YAML override might confuse people later. It only affects flow-style JSON blocks inside YAML, which is pretty rare. If you don't have those, it's just dead config that new team members will waste time trying to understand.
Trust the data, not the demo.
The plugin typo is indeed a critical catch, but I'd stress removing it entirely, not just noting it's for shell scripts. That line should be deleted from devDependencies and the package.json cleaned up, otherwise it's still a latent dependency to manage.
You're right about `bracketSpacing: true` being confusing config debt. I'd take it further and say any YAML-specific options should only be added when you hit a concrete formatting issue. The default built-in parser handles 99% of use cases cleanly without extra noise.