Developer Formatting

Code formatter

What to do
CSS
HTML
SQL
YAML
INI, TOML
.env
GraphQL
nginx, Apache
Indent

A .env file or a server config usually holds secrets. Nothing typed here leaves your browser, but paste with that in mind.

Processed in your browser · nothing is uploaded

Local · layout only, except .env and YAML
Advertisement
320 × 100

One box for ten syntaxes: CSS, HTML, SQL, YAML, GraphQL, INI, TOML, .env and brace-style server configs, plus JSON, which is here as a conversion partner for YAML rather than something this page formats — the JSON formatter does that. Formatting expands to one statement per line; where the indent is yours to choose, CSS, HTML, GraphQL and the server configs offer two spaces, four, or a tab, while SQL and YAML use their own conventional width. Minifying removes comments and whitespace and nothing else. Minified CSS is typically 20 to 30 per cent smaller before gzip.

How to format a file

1 Paste the file into the input box.
2 Choose the syntax and what to do with it: format, minify, or convert.
3 Where the operation indents, pick two spaces, four, or a tab.
4 Copy the result, or save it as a file.

Almost every operation on this page moves whitespace and line breaks and touches nothing else. No rule is merged, no selector renamed, no value rewritten, and that restraint is what makes the output predictable: the file you get back behaves exactly like the one you pasted in. Two passes are the deliberate exceptions and both are described below: the .env one, which rewrites keys and drops a line it cannot read, and the YAML one, which goes out through a parser and back, so type coercion applies and the comments do not come back. The interesting part everywhere else is the short list of places where whitespace turns out not to be decoration at all.

Where a space is part of the grammar

Four cases cover nearly every surprise. Inside CSS calc() the spaces around + and are required by the syntax, so calc(100% + 10px) closed up to calc(100%+10px) is invalid and the browser drops the declaration without a word. A descendant selector ending in a pseudo-class fails the same way: .a :hover becomes .a:hover, which matches something else entirely. That second shape is rare; the first is common enough to be worth a search through any minified stylesheet before you ship it. In HTML the gap between two block elements is free to remove and the gap between two inline ones is rendered, so closing it joins two words that were meant to stay apart — most often when the two spans sat on separate lines, which is how markup is usually written. And YAML is the extreme case, because there the indentation is the structure. A tab is not valid indentation in YAML at all, and reindenting is the one operation here that can change what a document parses to.

CSS and HTML

The safe transformations are the boring ones and they are most of the win: whitespace around braces, colons and commas is never significant, comments never affect rendering, and the semicolon before a closing brace is optional. Two things are deliberately not attempted. Duplicate selectors are never merged, because something declared between .a{color:red} and .a{padding:0} may override one of them and merging changes which rule wins. Colours and units are never shortened, because that is rewriting values, which is a different kind of tool with a different kind of risk.

The HTML minifier keeps pre, textarea, script and style byte for byte, keeps conditional comments, keeps every optional closing tag and reorders no attribute. Plenty of minifiers strip the quotes, drop the closing tags and shuffle the attributes; each of those is another way to be surprised by a page that used to work. Expect 20 to 30 per cent off a stylesheet and 10 to 20 off a page before compression, and considerably less after gzip, which is already very good at repeated whitespace.

SQL

The trap that catches naive SQL formatters is the keyword inside a string. WHERE note = 'sent from accounts' contains the word FROM, and breaking on it produces a query that no longer parses; literals are set aside here before any keyword matching happens, doubled apostrophes included. Two limits on that protection are worth knowing. It covers single and double quotes and stops there, so a PostgreSQL function body between $$ markers will be broken on as though it were part of the statement. And line comments are dangerous in the other direction: -- runs to the end of its line, so reflowing SELECT id, -- the id followed by name FROM t puts the column inside the comment. Strip the line comments first, or minify, which removes them properly.

One cosmetic detail looks like a bug and has an innocent cause. Keywords are upper-cased as they are broken on, and a keyword at the very start of the query has no break to make, so select id from t comes back with a lowercase select and an uppercase FROM. The SQL pass also takes no indent setting: its continuation depth is fixed, so the two-spaces-or-four choice above the box appears only for the operations that read it, which are CSS, HTML, GraphQL and the server configs.

Minifying SQL saves almost nothing worth having. Query text is a rounding error next to the work the database does, and a one-line query is much harder to read in a slow-query log. The genuine uses are a single-line config value, a migration tool that wants one statement per line, and a log line that must not wrap. The IN list is the other SQL job here: quoting is decided by looking at the values, so an all-numeric list stays bare for an integer column and a mixed list is quoted throughout. Oracle refuses more than 1,000 items in an IN list outright, and other engines accept far more while planning the query badly, so past a few hundred values a temporary table and a join is both faster and legal everywhere.

GraphQL

GraphQL has no formal formatting rules, so the convention is only what every tool converged on: two spaces per level, the opening brace at the end of the line it belongs to, one field per line. Commas between fields are legal and insignificant in exactly the way whitespace is, and dropping them is the convention because they add nothing.

The part a naive line-splitter breaks is that an alias and a directive stay attached to the field they belong to. short: reallyLongFieldName is one selection with an alias, and posts(first: 10) @include(if: $withPosts) is one selection with an argument list and a directive; splitting either on whitespace produces a document that no longer parses, so the split here tracks parenthesis depth and keeps both shapes whole. A schema formats the same way as a query, because type definitions are brace-nested identically — paste an SDL file in and it indents by nesting like anything else. And minifying is genuinely useful in one place only: a persisted-query hash. If the client and the server hash the query text, both have to normalise it identically or the hashes never match, which is a real deployment failure and the whole reason a GraphQL minifier exists.

YAML, and the Compose file

YAML formatting is a parse and a re-emit, which normalises indentation and quoting and fails loudly on input that does not parse. Anchors, aliases, tags and multi-document streams are refused with a message: expanding an anchor changes the document and dropping one destroys information, so declining is the only honest option. That refusal catches more Compose files than you might expect, because the x- extension fields people use to share a block of settings between services are written with an anchor.

Two further consequences of the round trip are worth stating plainly, since neither is what "format" suggests. Comments do not survive it. A comment carries no meaning in the parsed document, so there is nowhere for the parser to keep it, and the file comes back without the notes that were in it — copy them across by hand, or use the brace-config pass if all you wanted was indentation. And a line that is neither a key: value pair nor a list item now stops the pass and reports its line number instead of being skipped. That is the important half: a skipped line in a Compose file means a service quietly missing from an output that otherwise looks correct.

Type coercion is where YAML earns its reputation. Under YAML 1.1 the words yes, no, on and off are booleans, which is why the country code NO for Norway comes back as false, and why the version 1.10 becomes the number 1.1. Quote anything meant to reach its destination as text. A Compose file adds two of its own: an unquoted 22:22 is read as a base-60 number and becomes 1342, which is the reason the Compose documentation quotes port mappings even where it does not strictly need to, and DEBUG: true reaches the container as a boolean where the container wanted the string. Indentation carries the same weight here as anywhere else in YAML: a service nested one level too deep becomes a key of the service above it, and the error Compose reports is about an unexpected field, which sends people looking in the wrong place.

The config formats

INI has no specification, and that is the single most useful thing to know about it. Every parser invented its own rules and they disagree on whether ; or # starts a comment, whether a comment may follow a value, whether quotes are part of a value, whether keys are case-sensitive, and whether a duplicate key means the last wins or a list. Nothing here resolves any of that; it indents the entries under their section and writes each pair as key = value. Those spaces around the equals are the one thing to check against your own parser, since a few take them literally. TOML does have a specification, and the part people get wrong is that [dependencies] is not a section with an end. It sets the current table, and every key after it belongs to that table until the next header, which is why moving a key one line silently reparents it. Double brackets are the other one: [[bin]] declares an array of tables, so it is one block per binary, not one block you keep adding to.

A .env file breaks on a space, and the shape that does it looks entirely correct: KEY = value. Most loaders take everything after the first = literally, so the value arrives with a leading space that is invisible everywhere you would look for it. A URL that will not connect and a token rejected as invalid are usually this. So the .env pass is the one operation here that rewrites rather than reindents, and it is worth knowing exactly what it changes. It closes up the spaces around the equals, upper-cases the key into the A–Z 0–9 _ shape loaders expect, drops a leading export, and gathers the comments at the top of the file. It also re-quotes from the bare value: a value containing a space, a #, a quote or a $ gets quotes, because without them it is truncated, read as a comment or interpolated, and a value that needs none is left bare, since some loaders strip quotes and some do not. A line with no = on it is dropped. Sorting the keys is offered as its own operation, so plain formatting leaves the order as you wrote it. And a .env is not a shell script even though it looks like one, so keep values single-line and leave command substitution out.

nginx and Apache both ignore indentation entirely; what it buys you is seeing which block a directive belongs to, and in both servers that scope decides behaviour. An nginx directive inside a location does not merge with the same directive in the enclosing server block, it replaces it, which is how a proxy_set_header Host set at server level silently disappears the moment a location sets a header of its own. Apache containers borrow the shape of HTML and none of its behaviour: <Directory> sections are applied shortest-path-first, then <DirectoryMatch>, then <Files>, then <Location>, so a <Location> block near the top of the file overrides a <Directory> block at the bottom and reading top to bottom gives the wrong answer.

None of this validates anything

A formatter indents by depth and reports nothing. A misspelled property, an invalid colour, a directive whose module is not loaded and a path that does not exist all pass straight through. An unbalanced brace at least announces itself, as everything below it indented one level too deep. The authority on whether a config is correct stays the thing that loads it: apachectl configtest, nginx -t, docker compose config.

What people use it for

  • Indenting an Apache VirtualHost by container depth
  • Reindenting an nginx server block so a directive’s scope is visible
  • Expanding a minified stylesheet back to one declaration per line
  • Stripping comments and whitespace from CSS before a deploy
  • Fixing the indentation of a docker-compose.yml
  • Reindenting a YAML file and finding the line a parser choked on
  • Tidying a .env where a stray space broke a connection string
  • Turning a .env file into JSON for a secrets store
  • Pretty-printing a GraphQL query pulled out of a network tab
  • Minifying a GraphQL document so a persisted-query hash matches
  • Removing whitespace and comments from HTML without touching pre
  • Laying out an INI config so every section reads the same way
  • Formatting a Cargo.toml or a pyproject.toml by table
  • Breaking a one-line SQL query onto its keywords
  • Collapsing a query onto one line for a config value or a log
  • Turning a pasted column of ids into a SQL IN clause

Questions

No. It is a formatter, not a linter. An unbalanced brace shows up as everything below it indented one level too deep.

MDN, CSS referenceMDN, HTML referencePostgreSQL, SQL syntaxPostgreSQL, IN expressionsYAML 1.2 specificationThe Norway problem, YAML boolean coercionYAML 1.1, sexagesimal integersCompose file referenceTOML v1.0.0 specificationPython, configparser and INI syntaxThe Twelve-Factor App, configGraphQL specification, languagenginx, configuration file structureApache, configuration sections
Advertisement
300 × 250
Was this tool any good?
Internal signal only · I use it to find the tools worth rebuilding