Changelog
A tool that never changes is a tool nobody maintains. This page is dated so you can tell the difference between an active project and an abandoned one. Dates come from the actual commit history, not from the build clock.
2026-10-26
- Minify could change the value of a string literal.
minifySqlQueryfinished by running two whitespace regexes over the assembled output —\s*,\s*then\s+— so it rewrote the inside of quoted strings on its way to fixing token spacing.SELECT 'a,b'came back asSELECT 'a, b','a b'as'a b', and a JSONB path'{a,b}'became'{a, b}'. That is not a layout change; it is the data. It is also invisible on screen: the value grows a space and you find out downstream, in a CSV field, a delimiter, or a lookup key that no longer matches. Minify is exactly the operation people run before pasting a statement into a migration or a source constant, which is where it hurts most. The two regexes are gone — token spacing is decided while tokens are emitted, and literal text is copied verbatim. Every one of the 20 output differences this removal caused was confined to the inside of a literal; outside literal boundaries the old and new output are byte-identical, so nothing else changed behaviour. - The bug outlived a test suite that was strong enough to catch it. The losslessness checks already assert minify's code-token stream and every literal's exact value. What they lacked was a probe whose literal contained comma-adjacent or repeated whitespace — every sample literal in the file used single spaces, so the shapes that trigger the rewrite never appeared. A guard is only as good as the corpus that reaches it, so those shapes are now named cases (
'a,b','a b','a, b','Washington, D.C.', agroup_concatseparator, a JSONB path, several literals in one statement), checked in all four dialect modes, and the fix was verified by replanting the old code and confirming the suite fails with "minify rewrote the inside of a string literal". - The three dialect landing pages now hold different content.
/sql/postgres-formatter/,/sql/mysql-beautifier/and/sql/sqlite-minify/were still ~92% identical after the 10-19 pass gave each one a heading: the FAQ and the Pro Tips panel were both keyed by app, so all three rendered the homepage's copy verbatim — 863 duplicated words per page. Each route now has its own FAQ and its own tips file, and the evidence block under each is generated by running this very formatter over a fixed probe set at build time, so the before/after code on the page is measured output rather than prose about it. Route-to-route similarity went from 0.935 to 0.43, and a question may no longer appear on two routes. A route whose probes no longer differ from another mode fails the build instead of quietly shipping as a near-duplicate again. - A SQLite page listed syntax SQLite rejects.
/sql/sqlite-minify/offeredGROUP_CONCAT(x SEPARATOR ',')as a construct the tool preserves.SEPARATORis MySQL's spelling; SQLite takes two arguments,group_concat(x, ','), and the MySQL form is a syntax error there. The tool preserved the characters faithfully — which is how the claim looked true while being wrong. It is the same defect as the BigQuery sentence corrected below on 10-24: a sample that survives formatting is not evidence the syntax belongs to that engine. The probe and the tips text now use the two-argument form and say so.
2026-10-24
- The search-result description still named a dialect this tool does not have. The 2026-10-19 entry below says the SERP description was corrected away from "PostgreSQL, MySQL, SQLite, and BigQuery dialects". It was not: that pass rewrote the prose pages and missed the app config, where the same sentence lived in
metaDescription. So the false engine survived in three places — the search snippet, the Open Graph description, and theSoftwareApplicationstructured data — on the one sentence most people ever read. BigQuery is not a mode in the dialect box, and itsSELECT * EXCEPT (a, b)is read as a set-operationEXCEPT, so it breaks where a BigQuery reader would not expect; the guide on this site has said that all along while the description promised the opposite. The sentence now reads "Indents and uppercases PostgreSQL, MySQL and SQLite queries in your browser". - Why it is now enforced rather than just corrected. A gotchas list and a marketing sentence are both claims about code, and they rot the same way — by nobody re-checking them after the code moved. So the test suite derives the allowed engine list from the dialect select's own options, labels included, and fails if any description names an engine the box cannot be set to. The per-engine landing pages are held to their own option, which is why the MySQL page may say MariaDB and the SQLite page may not say MySQL. Add a real mode to the select and the permitted sentence widens by itself; name an engine with no option and the run fails with that engine named. The check was tested by replanting the old claim and confirming it fails, and it also rejects a description emptied out to dodge it.
2026-10-19
- A dialect box, and it changes exactly two things. Two SQL spellings mean opposite things in two engines and no parser can tell them apart from the text: a bare
#(a MySQL line comment, or PostgreSQL's integer XOR) and a backslash inside single quotes (a MySQL escape, or a literal character under PostgreSQL'sstandard_conforming_strings— the default since 9.1 — and in SQLite). The formatter had to guess, and its guess followed MySQL: a PostgreSQL query using#as XOR lost everything after it, and a string ending in a backslash —'C:\', the Windows-path case — fused with the following literal and reflowedFROMinside what had been one string. The select (Auto / PostgreSQL / MySQL / SQLite) resolves both readings; the layout pass itself is identical in every mode, and Auto keeps the old MySQL behaviour, which fails visibly instead of silently. Losslessness is now asserted per literal value, not just against whitespace-stripped text — the old check could not see a newline injected inside a string. - The dialect landing pages had no dialect in them.
/sql/postgres-formatter/,/sql/mysql-beautifier/and/sql/sqlite-minify/differed from each other only in their<meta>tags: the same 216 visible words, the same "POSTGRES / MYSQL / SQLITE" label, no<h1>anywhere in the body. Each route now renders its own heading, engine label and intro, and pre-selects its dialect the way the curl tool pre-selects a target language. The intros say plainly which two readings the mode changes, because a page implying four parser modes would be a claim this code does not support. - The formatter no longer deletes PostgreSQL
#-prefixed operators.#>,#>>and#-all start with#, which is MySQL's line-comment introducer, and the comment rule ran before the operator tables — soSELECT meta #- '{a}' FROM tcame out asSELECT meta. No error, and the result still looked like valid SQL. A bare#is still a comment, because that is genuinely ambiguous without a dialect mode and this tool has none. - The guide on comment loss was wrong and has been rewritten against the current code. It described the old minifier, which collapsed newlines first and let a
--swallow the rest of the statement. The current code removes comments outright, in all three styles — including block comments, which the old page told you to rely on. So the advice was the opposite of what you need:/*keep*/does not survive here. The page now states what happens, adds the unterminated-/*truncation and nested-comment cases it previously declared "not verified", and ships a repro command that proves it is testing the deployed code. - Copy that promised features this tool does not have has been corrected. The search-result description claimed support for "PostgreSQL, MySQL, SQLite, and BigQuery dialects", the About page sold "dialect selection for the four engines", the porting guide described choosing a dialect "for presentation", the contact page asked bug reporters to "name the dialect you selected", and
/sql/sqlite-minify/was called a "Single-Line Optimizer" (nothing is optimised; comments are deleted). None of it was true of the code at the time it was written. The pages now describe what the tool actually does, including the dialect box that shipped the same day and the two readings it changes.
2026-10-08
- Ads are now decided by rendered fill, not by tag presence. The page previously hid or showed ad slots based on whether the ad script had loaded. That is not the same thing as an ad rendering. The check now waits for a real creative with non-zero dimensions, so a page stops flashing empty grey boxes when nothing fills.
- Sitemaps are generated from build output instead of being hand-maintained, and only for domains that actually resolve. Hand-written sitemaps drift; a stale
<lastmod>teaches crawlers to ignore the field entirely.
2026-10-06
- Contrast fixes across all pages to meet WCAG 2.1 AA. Muted text on the dark theme and the primary button's hover state both failed the 4.5:1 ratio. Also gave the dialect/indent
<select>a real accessible name.
2026-10-04
- Footer rebuilt as a labelled link grid, and the header navigation made consistent with the other sites in the family.
/tools/hub page added, listing every tool and guide on this domain from one place.
2026-10-01
- Guides published: SQL cheat sheet, reading EXPLAIN ANALYZE, SQL hacks, plus patterns and gotchas, best practices, alternatives, and migration safety.
- Related-guides blocks added beneath each guide, so a page connects to its neighbours instead of sitting alone.
- 404 and contact pages generated at build time. A soft 404 — an error page that returns status 200 — is one of the more common reasons a small site fails an ad-network review, and it is entirely avoidable.
2026-09-15
- Build and SEO plumbing: programmatic routes, sitemap generation, and a second ad provider as fallback.
2026-09-16
- Sitemap
lastmodvalues refreshed and lockfiles updated. (No formatter changes that day — the defect fixes and fuzzing harness from the same period landed on the JavaScript formatter at jsformat.dev, not here. Commit history is public if you want the real timeline.)
First release
- Client-side formatter: keyword-anchored layout, UPPERCASE toggle, indent control, minifier, dialect selection. Written with no parser on purpose — see what the formatter actually does for the consequences.
Something broken or a formatting rule you disagree with? Tell me — defect reports are the most useful mail this site gets.