Prettifying and minifying feel like opposite tools. They are the same operation: parse the input into a syntax tree, discard the original formatting entirely, and print the tree back out. Only the printing rules differ, one optimising for a human reading it and the other for bytes on the wire.
Almost every surprising formatter behaviour follows from that sentence.
Why a formatter refuses broken code
If the parser cannot build a tree, there is nothing to print. That is why a formatter reports an error and changes nothing rather than doing its best on the parts it understood.
This turns out to be useful. Running a formatter on a file is a fast syntax check, and the error location is usually within a line or two of the real problem. The same applies to XML, where a formatter that refuses to run has told you the document is not well-formed, which is often the actual question you had.
It also explains why formatted output sometimes differs from what you wrote in ways you did not ask for. You did not ask for your single quotes to become double quotes; the formatter is printing string literals according to its own rule, because your original quoting was not preserved anywhere.
What each language lets a formatter change
CSS is the safest. Whitespace between tokens is never significant. Minifying can remove all of it, shorten #ffffff to #fff, collapse margin: 0px to margin: 0, and drop the final semicolon in a block. The only real hazard is that CSS is order-dependent, so a minifier that reorders declarations can change specificity outcomes. Most do not, for that reason.
JavaScript is mostly safe with one famous exception. Automatic semicolon insertion means line breaks can be syntactically significant, so a minifier joining lines has to insert semicolons correctly. Modern minifiers get this right. Beyond formatting, real minifiers also rename local variables to single letters and remove dead branches, which is where most of the size saving comes from.
HTML is where it gets risky.
Also worth knowing: the contents of <pre> and <textarea> are significant and must be left alone, which good formatters handle and quick regex-based ones do not.
SQL is a special case, because the database does not care at all. Formatting SQL is purely for humans: consistent keyword casing, aligned clauses, indented joins, so a 40-line query can be read. There is no performance reason to minify it, and doing so makes the query log unreadable. Format it for the repository, and never think about minifying it.
XML has the same whitespace hazard as HTML, formalised. Whether whitespace inside an element is significant depends on xml:space and on the schema. Pretty-printing an XML document that is about to be digitally signed will invalidate the signature, because the bytes changed.
Minifying is largely obsolete for delivery
This is worth saying because a lot of advice has not caught up.
Every HTTP server worth using compresses responses with gzip or Brotli. Those algorithms are extremely good at repeated patterns, and indentation is the most repetitive content in a file. Minifying before compressing therefore saves far less than the uncompressed numbers suggest, often in the low single-digit percentages for CSS and HTML.
Where minification still earns its place is JavaScript, and not because of whitespace: it is the variable renaming, dead code elimination and tree shaking that a bundler does, which compression cannot replicate because those change the code rather than its representation.
So the honest position is that your build tool already does this, and manually minifying files is rarely the win it appears to be.
Where these tools actually help
Formatters are most useful away from the build pipeline:
- Reading someone else's minified output. Prettifying a vendor bundle to work out what it does.
- Inspecting an API response. A wall of single-line JSON or XML becomes legible.
- Checking syntax fast. A formatter that refuses to run has found your unclosed brace.
- Normalising before a diff. Two files that differ only in indentation produce an enormous diff. Formatting both with the same rules first reduces it to the real changes, which pairs well with a diff checker.
That last one is the underrated one, and it is worth reaching for before spending twenty minutes reading a diff that is mostly whitespace.