How to write an EditorConfig file

By

Write an EditorConfig file with the keys from specification 0.17.2. Indent, line endings, charset, a Markdown exception, and a Makefile that needs tabs.

Free toolThis tutorial uses the EditorConfig Generator. It runs in your browser, so open it in another tab and follow along.

An .editorconfig file tells editors how to format a file before anyone argues about it. Indent with spaces or with tabs. How wide a tab is. Which line ending. Which charset. Whether to trim trailing whitespace. Whether the file ends with a newline.

The file is INI-shaped. A line of root = true can sit at the top, before any section. Every other key has to live under a section such as [*] or [*.md]. A key that sits outside a section does nothing. Editors that support EditorConfig read the file from the directory of the file you have open, then they walk up to parent directories, until they hit a file that says root = true or they run out of parents.

The EditorConfig generator builds that file from the keys in specification 0.17.2. You pick the indent, the line ending, and the charset. You can add a Markdown section and a Makefile section. You copy the file, or you download it as .editorconfig.

How an EditorConfig file is appliedA file matches the star section first, then a later section overrides the keys it sets. root true stops the search in parent directories.File you open[*] sectionA later section, ifit matchesEditor uses themerged keysroot = trueStop at thisdirectory

A project file

The sample on the page is a rooted file, two-space indent, LF, UTF-8, trailing whitespace trimmed, a final newline, plus the Markdown and Makefile sections.

root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[{Makefile,makefile}]
indent_style = tab

The summary is the file, including the newline at the end. That trailing newline is insert_final_newline applied to the config file itself. The download uses the same bytes.

root = true is the preamble. With it set, an editor that opens a file in this tree will not keep walking into a home directory or a parent repo that has its own .editorconfig.

[*] matches every file. indent_style = space and indent_size = 2 means the editor inserts two spaces when you press Tab, and it treats an indent as two columns. end_of_line = lf is a line feed, the ending you want in a git repo unless the project is stuck on Windows tools that require CRLF. charset = utf-8 is UTF-8 without a BOM. trim_trailing_whitespace = true deletes spaces at the end of a line on save. insert_final_newline = true keeps a newline at the end of the file, which is what POSIX text files are supposed to have and what diffs stay quieter with.

Two notes come with the sample.

The [*.md] section turns trim_trailing_whitespace off. Two spaces at the end of a line are a Markdown line break.

Make requires a tab at the start of a recipe line. The Makefile section sets indent_style to tab.

Why Markdown is a special case

CommonMark treats two spaces at the end of a line as a hard line break. If the editor trims trailing whitespace on save, it deletes those line breaks and the paragraph collapses. The [*.md] section sets trim_trailing_whitespace = false and leaves every other key alone. The star section still applies, so Markdown stays at two spaces and LF. Only the trim is overridden.

A later section wins on the keys it sets. It does not erase the keys it does not mention. That is the whole model. Put the general rules in [*]. Put the exceptions after it. The spec says sections are read in order, and the last matching section supplies the value for each key it contains.

If you write Markdown and you never use the two-space break, you can turn the Markdown section off. Trailing spaces will be trimmed, same as your code. Turn it on if anyone on the project uses that break, because one save from a teammate’s editor will otherwise eat it.

Why Make is a special case

A Makefile recipe has to start with a tab. Spaces are a syntax error, and Make’s error message is the famous one about a missing separator. The section [{Makefile,makefile}] matches either file name. Brace lists are part of the EditorConfig glob rules. The section sets indent_style = tab and nothing else, so the indent size, the line ending, and the charset still come from [*].

indent_size stays 2 in the star section. For a tab indent, the spec says indent_size is the number of columns used to show a tab, and tab_width defaults to indent_size when you leave it out. The page leaves tab_width out in the sample because you did not set a separate width. Make does not care about the display width. It cares that the byte at the start of the recipe is a tab.

A tab project, a BOM, and a spelling language

Change indent to tab, set indent_size to 4, set tab_width to 4, turn root off, set the charset to utf-8-bom, set the spelling language to en-US, and turn both extra sections off.

root = false

[*]
indent_style = tab
indent_size = 4
end_of_line = lf
charset = utf-8-bom
spelling_language = en-US
trim_trailing_whitespace = true
insert_final_newline = true

Three notes:

root = false is the same as leaving root out. Parent directories are still searched.

utf-8-bom is discouraged by the EditorConfig spec.

tab_width matches indent_size, so it was left out. The spec says tab_width defaults to indent_size.

The file still starts with root = false. That value does not stop the search. Parent directories are still searched. Set root when this file is the top of the tree. Leave it off when this file is a subdirectory that should inherit from the repo root.

utf-8-bom is a legal charset. The spec says it is discouraged. A BOM at the start of a file confuses shebangs, some linters, and the occasional tool that compares bytes. Prefer utf-8 unless you are matching a file that already has a BOM and you have a reason to keep it. The page still writes the value if you pick it, and it says so.

tab_width = 4 next to indent_size = 4 is the default, so the line is dropped. Set tab_width only when it differs. A common case is indent_style = tab with indent_size = tab, which means the indent width follows the editor’s own tab size, plus a numeric tab_width for tools that want a number. The page allows indent_size to be the word tab. If the style is spaces and the size is tab, it adds a note: indent_size = tab with indent_style = space means the indent width follows the editor tab size.

spelling_language is the language an editor should spell-check in. en is a language. en-US is a language and a region. The form is two letters, or two letters, a hyphen, and two letters. Anything else is refused.

What the page refuses

indent_size of 0, or 2.5, or two, fails. indent_size must be a positive whole number, or tab.

tab_width of 0 fails the same way. tab_width must be a positive whole number.

A spelling value of english fails. spelling_language must be two letters, or two letters, a hyphen, and two letters, like en or en-US.

indent_size is written in lowercase, so Tab becomes tab. The spelling language is not lowercased. The region stays uppercase. en-us is refused, and en-US is accepted. The spec treats lf and LF as the same end of line. The file writes lf, because that is the value the form stores.

Unset keys are omitted. If you set end of line to “omit”, there is no end_of_line line. The editor keeps its own default. That is different from setting a value. An omitted key does not override a parent .editorconfig. A set key does.

When a formatter is the better tool

EditorConfig is a hint to editors. It does not rewrite the files already in the repo. Open a file, and the editor applies the rules to what you type next. A file that is already indented with tabs stays that way until someone formats it.

Prettier, and the formatter for a given language, rewrite the file. The Prettier post covers that side: a config, a command, the same bytes out of every machine. Use EditorConfig so the editor agrees with the formatter while you type. Use the formatter so the files on disk agree with each other. The two are not substitutes. A project can have both, and they should name the same indent and the same line ending, or you will watch a save fight a format.

VS Code can also set indent per language in settings.json. The language-specific settings post shows a block per language, with editor.tabSize and editor.insertSpaces. That file is yours. It does not travel with the repo. .editorconfig does. Put the project rules in the repo. Put your personal exceptions in your editor settings, and expect the project file to win where a core is installed.

The ESLint config generator, the tsconfig generator, and the .gitignore generator are the same kind of page for three other files a new repo needs. None of them formats whitespace. They belong next to this file, not instead of it.

The choices are stored in the URL, so you can hand someone a link and they see the same file. Nothing is uploaded. The spec text, if you want the full glob rules and the unset value, is at spec.editorconfig.org.

Try the EditorConfig Generator

Build an .editorconfig file from the keys in the EditorConfig 0.17 spec. Indent, line endings, charset, and Markdown and Makefile sections.

Open the EditorConfig Generator →

  • ESLint Flat Config Generator: Answer a few questions, get a commented eslint.config.js for JS or TS, React, Vue, or Astro — plus the exact install command.
  • tsconfig.json Generator: Answer six questions and get a commented tsconfig.json for TypeScript 5.x — browser, Node, or library setups.
  • .gitignore Generator: Check your stacks (Node, macOS, VS Code, Python, Astro, env files) and copy a commented .gitignore.

More tool tutorials →

Want me to talk about your product? You can sponsor this site.