SQL Formatter

Lay out a query so you can read it, or squash it onto one line

The query

    How to lay it out

    Formatted

    Paste a query and it gets laid out as you type. Nothing is sent anywhere, so a query with real table names and real values in it stays on your machine.

    Why this reads the query instead of matching patterns

    SELECT note FROM t WHERE note = 'sent from home'
    
    A formatter that looks for the word FROM with a
    regular expression finds two of them and puts a
    newline in the middle of the string.
    
    The query still runs. It just says something
    different now.

    Most quick formatters are a stack of find and replace rules: put a newline before FROM, before WHERE, before JOIN. That works until a query contains one of those words inside a string, a column name or a comment, and then it quietly corrupts the thing you pasted.

    So this tokenises first. Strings, comments, quoted identifiers, numbers and bare words all come out as separate pieces, and the layout rules only ever look at pieces they can identify. A FROM inside a string is a string, and it comes out exactly as it went in.

    Every dialect's quoting at once

    MySQL        `my table`
    SQL Server   [my table]
    Standard     "my table"
    Postgres     $$ a whole function body $$
    
    All four are read. None is rewritten as another,
    because changing the quoting can change which
    database will accept the result.

    Nobody wants to pick a database from a dropdown before pasting a query, so all four quoting styles are accepted together. Backticks, square brackets, double quotes and Postgres dollar quoting are each recognised and each left alone.

    Doubled quotes inside a string are handled, so 'it''s' stays one value, and backslash escapes are accepted because MySQL allows them. An unterminated string or block comment runs to the end instead of sending the parser into a loop.

    The AND that must not move

    WHERE created BETWEEN '2026-01-01' AND '2026-12-31'
      AND status = 'open'
    
    Two ANDs. The first belongs to the BETWEEN and
    must not move. The second is a new condition and
    should start a line.

    Breaking AND and OR onto their own lines makes a long WHERE clause readable. Doing it to the AND in a BETWEEN splits an expression in half and makes it look like a condition that got cut off.

    So the formatter looks back a few tokens: if a BETWEEN turned up before any other clause keyword, the AND belongs to it and stays put. It is a small rule and it is the difference between output you trust and output you have to check.

    Short brackets stay put

    Broken up:            Left alone:
    
    WHERE x IN (          WHERE x IN (1, 2, 3)
      1,
      2,
      3
    )
    
    Both are correct. Only one is readable.

    A formatter that breaks every bracket onto its own lines is technically consistent and unpleasant to read. COALESCE(a, b) andIN (1, 2, 3) are single ideas and belong on one line.

    Whether a group is short enough can only be known once it has been laid out, so that pass runs last: anything under sixty characters that does not contain a query of its own gets pulled back up. Subqueries always keep their own layout, because a subquery is a query and reads like one.

    Formatting twice changes nothing

    Running the formatter over its own output gives the same text back. That sounds obvious and plenty of formatters fail it, usually because a rule adds a newline that a later rule counts as meaningful.

    It is worth having because it means you can paste formatted SQL back in without watching it drift, and it is checked against a set of real queries on every change.

    What it does not do

    It does not validate. A query with a missing bracket or a misspelled keyword still gets laid out, because a formatter that refuses to work on broken SQL is useless exactly when you need it. Unbalanced brackets are counted and mentioned underneath instead of treated as a failure.

    It does not know your schema, so it cannot tell a table from a function or expand a SELECT *. The table names it lists are just the words that followed FROM, JOIN and UPDATE, which is right often enough to be useful and not something to rely on.

    A semicolon resets the indenting, so one statement with an unclosed bracket cannot push everything after it off the right hand side of the screen.