SQL Minifier_
Minifying SQL saves nothing at runtime. The server parses a statement once and whitespace costs it nothing measurable, so the bytes you remove buy no speed at all — you do this to move a query, into a log line, a JSON field, a config value, a CI variable or a shell argument, all of which want one line.
Which makes the only thing that matters correctness. Strip the newline after a -- comment and everything following it is commented out; drop a /*! block in MySQL and you have deleted a statement that actually runs. This tokenises first, so strings, quoted identifiers and dollar-quoted bodies come through byte for byte.
- Input
- A query or a script, in standard SQL, PostgreSQL, MySQL, SQL Server or SQLite. The dialect decides how identifiers and string literals are quoted.
- Output
- One line. Comments removed by default, or kept — in which case line comments become block comments, since a -- cannot survive on a single line.
- Processing
- Tokenised in this tab before anything is removed. Strings, quoted identifiers and dollar-quoted bodies are emitted byte for byte and never re-cased.
- Limits
- It does not parse the grammar, so it will not tell you whether the query is valid. When the tokeniser is not confident — an unterminated string, usually — it falls back to collapsing whitespace and says so rather than guessing.
- Two things that look like comments and are not
- /*+ … */ is an optimizer hint and removing it changes the execution plan. /*! … */ is a MySQL executable comment — the contents run in MySQL and are invisible to every other engine, which is how mysqldump ships version-gated statements. Both are kept even when comments are being removed, because neither is a comment.
Minifying SQL buys you nothing at runtime
The server does not care about whitespace
This is the difference between minifying SQL and minifying CSS or JavaScript. Those are shipped to every visitor over a network, so bytes are the point. A query is parsed once by a server that has already read it off a socket, and the parse is a rounding error next to planning and execution — and where prepared statements or a plan cache are involved it happens once for many executions. Nobody has ever made a query faster by removing its indentation. If a tool tells you otherwise, it is selling the wrong benefit.
You do it to move the query, not to run it
The real reasons are all about transport. A log line is one line, so a multi-line query becomes several entries that nothing can correlate. A JSON string cannot contain a raw newline. A YAML or .env value on one line is far easier to get right than a folded block. A shell argument with newlines needs quoting nobody enjoys. A migration tool, an ORM annotation, a monitoring check — each of them has a field that expects a single line, and that is what this is for.
The line comment is the trap
A -- comment runs to the end of the line, and joining lines is exactly what minifying does. Collapse the newline without understanding that and every token after the comment becomes part of it — the query either fails outright or, far worse, succeeds as a shorter query with a different meaning. This is why minifying SQL with a regular expression is not a shortcut but a hazard, and it is why a correct minifier has to tokenise before it removes anything. Keeping comments is possible, but only by rewriting each line comment as a block comment.
Some comments are executable code
/*+ INDEX(t idx) */ is an optimizer hint in Oracle and MySQL, and removing it changes the plan the database chooses — a "cosmetic" edit that turns an index scan into a table scan. /*!40101 SET NAMES utf8 */ is stranger still: MySQL executes the contents when its version is at least the number given, and every other engine sees a comment. It is how a mysqldump file runs on MySQL and stays portable elsewhere. Strip those and you have not removed a comment, you have removed a statement.
Everything inside quotes is data
A string literal can contain newlines, runs of spaces, and the characters -- and /*, none of which mean anything inside it. So can a quoted identifier — "my column" in standard SQL, `my column` in MySQL, [my column] in SQL Server — and a PostgreSQL dollar-quoted body, which is usually a whole function with its own comments and layout inside it. All of them are passed through untouched here, which is the only correct behaviour and the one a naive minifier gets wrong first.
What you give up
A one-line query is unreadable, undiffable and hard to edit. If it lands in a slow-query log the person reading it at three in the morning has to reformat it before they can think about it, and if it lands in version control every future change to it is a single-line diff that shows nothing useful. Minify at the boundary — when the query is being put somewhere that needs one line — and keep the readable version as the source. Going the other way is what the SQL formatter is for.
Paste, pick the dialect, copy one line
- 01Choose the dialect. It decides how identifiers are quoted — backticks in MySQL, brackets in SQL Server — and getting it wrong is how a column name gets treated as a string.
- 02Paste the query. The result updates as you type.
- 03Read the notes. They say what was removed and, more usefully, what was deliberately kept because removing it would have changed the query.
- 04Turn on Keep comments if the destination can carry them. Line comments are rewritten as block comments, because a -- would swallow the rest of the line.
- 05Keep the formatted version as your source of truth and minify at the point of use, not in the repository.
A query going into a log line
Multi-line SQL becomes several log entries that no aggregator will correlate, and the query is unsearchable across them.
SELECT id, email FROM users -- only the active ones WHERE active = 1
SELECT id, email FROM users WHERE active = 1
A regular expression that broke the query
Newlines were stripped without understanding the line comment, so the rest of the statement became part of it.
SELECT a FROM t -- filter WHERE x = 1
SELECT a FROM t The WHERE clause is inside the comment. Every row comes back.
A mysqldump file that stopped working
The /*! blocks were treated as comments and removed. They were not comments — MySQL executes them.
/*!40101 SET NAMES utf8 */;
The dump loads with the wrong character set. Kept here, always.
A query embedded in JSON
A JSON string cannot contain a raw newline, so the query has to be one line before it can be a value at all.
one line, then escaped
Minify here, then escape with the JSON escape tool. Escaping first leaves \n in the query.
Which constructs survive minification
| Construct | Treatment | Why |
|---|---|---|
| Indentation and line breaks | Collapsed to single spaces | The only thing that is genuinely free to remove |
-- line comment | Removed, or rewritten as a block | It runs to end of line. Joining lines without handling it comments out the rest of the query |
/* block comment */ | Removed by default | Safe to remove — it has an explicit end |
/*+ hint */ | Always kept | An optimizer hint. Removing it changes the execution plan |
/*! … */ | Always kept | MySQL executes this. It is code wearing a comment as a disguise |
'string literal' | Byte for byte | Its whitespace is data. So is a -- inside it |
"quoted" `ident` [ident] | Byte for byte, never re-cased | A quoted identifier is case-sensitive and may contain spaces |
$$ dollar quoted $$ | Byte for byte | Usually a whole function body, with its own comments and layout |
| Keyword case | Left exactly as written | Changing it is a formatting decision, not a minification one |
Nothing on this list is removed because it is small. Whitespace is removed because it carries no meaning; everything else is kept because it does.
Working with minified SQL
- Do not minify for speed. The parse is not your bottleneck, and a plan cache makes it not even a repeated cost.
- Keep the formatted query as the source. Minify on the way into a log, a config value or a JSON field, and never the other way round.
- Set the dialect before you trust the output. Backticks are identifiers in MySQL and something else everywhere else.
- Minify before escaping, when a query is going into JSON. Escaping first turns real newlines into \n and you end up escaping them twice.
- Never build a query by concatenating a minified string with user input. One line makes it easier to write and no safer — parameters are the only answer.
- Expect a one-line diff. A minified query in version control tells you that it changed and nothing about how.
Where minifying SQL goes wrong
A line comment swallows the rest of the query
This is the failure that matters. Remove the newline after a -- without knowing it is there and every token after it is commented out. The query may still run, return fewer conditions than it should, and look fine.
Optimizer hints are not decoration
/*+ … */ tells the planner which index or join order to use. Stripping it as a comment is a silent performance change that no diff of the results will reveal.
MySQL executable comments are statements
/*! … */ runs in MySQL. A dump file relies on it to set the character set, disable key checks and restore them, and removing those blocks corrupts the restore rather than tidying the file.
Whitespace inside a string is data
Collapsing spaces inside a literal changes the value being compared or inserted. A minifier that does not tokenise cannot know where a string starts, and quoted identifiers and dollar-quoted bodies have the same problem.
Minified SQL is harder to review
It hides structure from the reader and from the diff, which matters most for exactly the queries that are complicated enough to want minifying. Keep a readable original.
Tokenising, dialects and fallback
- Approach
- The input is tokenised first, so removal decisions are made per token rather than per character. A regular expression cannot do this correctly, because it cannot know whether a -- is inside a string.
- Dialects
- Standard SQL, PostgreSQL, MySQL, SQL Server and SQLite — differing in identifier quoting (double quotes, backticks, brackets), dollar quoting, and escape-string literals.
- Kept always
- Optimizer hints (/*+ … */) and MySQL executable comments (/*! … */). Neither is a comment in any sense that matters, and both are kept even with comment removal on.
- Untouched
- String literals, quoted identifiers and dollar-quoted bodies are emitted byte for byte. Keyword case is left exactly as written.
- Keeping comments
- Line comments are rewritten as block comments, and any */ inside one is defused, since a comment that closes itself early would break the statement.
- Fallback
- If the tokeniser is not confident — an unterminated string is the usual cause — the tool collapses whitespace only and says so, rather than removing things it cannot account for.
- Network
- None from tool code. A test sweep calls every function this page uses with
fetchandXMLHttpRequestreplaced by stubs that throw, so a stray request fails the build instead of shipping. Disconnect from the network and the page still works.
Questions about minifying SQL
Does minifying SQL make queries faster?
No. The server parses the statement once, and parsing is negligible next to planning and execution — with a prepared statement or a plan cache it happens once for many runs. Removing whitespace from SQL is not comparable to minifying CSS or JavaScript, which are sent to every visitor over a network.
Why minify SQL at all then?
To move it. A log line, a JSON string, a YAML or .env value, a CI variable and a shell argument all want a single line, and a multi-line query in any of them is either broken or unusable. Minification is a transport step, not an optimisation.
Is it safe to remove comments from SQL?
Ordinary ones, yes. Two forms are not comments: /*+ … */ is an optimizer hint and removing it changes the execution plan, and /*! … */ is executed by MySQL and ignored by everything else. Both are kept here even when comments are being removed.
What happens to -- comments when SQL is put on one line?
They have to be removed or converted, because a -- comment runs to the end of the line and joining the lines would put the rest of the query inside it. That is the single most common way a minified query silently changes meaning, and it is why this cannot be done with a regular expression.
Will minifying change my string literals?
No. Everything between quotes is data, including runs of spaces, newlines and sequences like -- and /* that would mean something outside. Quoted identifiers and PostgreSQL dollar-quoted bodies are treated the same way, byte for byte.
Does it validate the SQL?
No, and it does not need to. It tokenises rather than parses, so it can tell a string from a comment from an identifier without knowing whether the statement is well formed. If the tokeniser hits something it cannot account for, it collapses whitespace only and tells you.
Should I commit minified SQL?
Almost never. It hides structure from readers and from diffs, so a change to a complex query shows as one modified line. Keep the formatted query as the source and minify at the point where a single line is required.
How do I put a query into a JSON field?
Minify first, then escape. Escaping first turns the real newlines into \n inside the value, and minifying afterwards cannot tell those from anything else. The order matters and it is the wrong way round more often than not.
What is the difference between minifying and formatting SQL?
Opposite directions with the same requirement. Formatting adds structure for a reader; minifying removes it for a channel that cannot carry it. Both have to understand strings, comments and quoted identifiers or they will change what the query does.
Is the SQL I paste here uploaded?
No. The work is JavaScript running in this tab. Every function it calls is covered by a test that stubs fetch and XMLHttpRequest to throw, so a request that slipped in would break the build rather than reach a server — and you can confirm it for yourself by disconnecting and carrying on.