SQL Formatter — Database Query Beautifier & Style Reference
Complete technical guide to SQL query formatting, AST tokenization, dialect syntax rules, multi-line indentation standards, and programmatic code implementations across JavaScript, TypeScript, Node.js, and Python.
1. SQL Formatting Fundamentals
SQL formatting (also referred to as SQL beautification or pretty-printing) is the process of restructuring raw Structured Query Language text to enforce consistent layout, indentation, line breaks, and keyword capitalization. Unlike programming languages that use strict block delimiters or forced whitespace (like Python), standard SQL is a free-form declarative language. A database engine parses SELECT id, name FROM users WHERE active = true; identically whether written as a single line, spread across ten lines, or formatted with arbitrary spaces.
However, while database parsers are indifferent to whitespace, human software engineers and database administrators (DBAs) rely heavily on visual layout to understand query structure. In modern software engineering, raw SQL queries are frequently embedded inside application source code, ORM log files, migration scripts, and analytical dashboards. Unformatted SQL queries—especially those containing multiple JOIN clauses, nested subqueries, CASE expressions, and window functions—become opaque walls of text that invite logical bugs and delay code reviews.
Formatting vs. Validation
Formatting alters the visual layout, spacing, and capitalization of code without modifying its underlying logical AST structure. Validation parses the query against database grammar rules to detect syntax errors (e.g., missing keywords or unbalanced parentheses). ToolMono SQL Formatter formats text layout safely while preserving exact query logic.
Formatting vs. Minification
Formatting adds line breaks, spaces, and indents to maximize human readability (~2,500 words of documentation depth). Minification strips comments, extra spaces, and newlines to shrink payload sizes for network transfer or inline execution. For payload reduction, use our SQL Minifier.
Team Collaboration & Reviews
Enforcing a unified SQL formatting standard across engineering teams streamlines Git code reviews. One-column-per-line formatting ensures that adding or modifying a column produces clean single-line Git diffs instead of altering entire monolithic query strings.
2. SQL Syntax Structure & Clauses
Relational SQL queries are constructed from distinct grammatical components. A robust formatter recognizes the logical hierarchy of these elements and places each clause at an appropriate indentation level:
Major Query Clauses
Major clauses form the primary backbone of an SQL statement: SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, INSERT INTO, UPDATE, SET, DELETE FROM, and WITH. Formatter standards place each major clause at the root margin (0-space indentation) or align them consistently along left verb boundaries.
Join Expressions & Table References
Table join operations—including INNER JOIN, LEFT OUTER JOIN, RIGHT JOIN, FULL JOIN, and CROSS JOIN—define relational paths between tables. Formatter rules place each JOIN statement on a new line with 2-space or 4-space indentation, keeping the ON join condition aligned with the join table reference.
Subqueries & Common Table Expressions (CTEs)
Subqueries nested inside WHERE IN (...) clauses or FROM table expressions, as well as CTEs declared in WITH cte_name AS (...) blocks, introduce nested scope levels. The formatter increases indentation by one full level (e.g., 2 spaces) for every nested parenthetical scope and aligns closing parentheses with the initiating clause keyword.
Window Functions & Conditional CASE Statements
Analytical window functions (OVER (PARTITION BY ... ORDER BY ...)) and conditional logic (CASE WHEN ... THEN ... ELSE ... END) contain nested sub-expressions. Formatter engines expand CASE statements across multiple lines, indenting WHEN, THEN, ELSE, and END keywords to ensure rapid auditing during business logic reviews.
3. How SQL Formatting Works
ToolMono SQL Formatter transforms raw input strings through four distinct computational stages:
Stage 1: Lexical Tokenization
The input string is scanned character-by-character to extract typed tokens: SQL Reserved Keywords (SELECT, JOIN), Table/Column Identifiers, String Literals ('active'), Numeric Values, Operators (=, >=, +), Delimiters (commas, semicolons), and Comments (--, /* */). Quoted literals and comments are isolated so their internal text is never modified.
Stage 2: Syntactic Tree Building & Scope Analysis
Tokens are grouped into a hierarchical Abstract Syntax Tree (AST) or token stream that tracks clause depth, parenthetical nesting levels, subquery boundaries, and dialect-specific constructs (such as PostgreSQL :: type casts or MySQL backtick quoting).
Stage 3: Keyword Casing & Indentation Rule Application
The engine applies configurable formatting rules: converting unquoted SQL keywords to uppercase, inserting mandatory line breaks before major clause keywords (FROM, WHERE, GROUP BY), placing projected SELECT columns on individual lines, and assigning relative indentation increments (e.g., 2 spaces) per nested scope level.
Stage 4: Whitespace Serialization & Rendering
The transformed token stream is serialized into the final formatted string with normalized spacing around operators (a = b instead of a=b), cleaned line breaks, and preserved comment blocks. The entire process completes in browser memory in under 5 milliseconds.
4. SQL Formatting Styles & Conventions
While individual database teams may adopt specific style variations, standard professional SQL formatting adheres to these core style rules:
Uppercase Keyword Standardization
All built-in language keywords (SELECT, FROM, WHERE, AND, OR, ON, AS, NULL, TRUE, FALSE) and aggregate function names (COUNT, SUM, AVG, COALESCE) are capitalized to distinguish them from user identifiers.
One Column Per Line Projection
In SELECT clause projections, each column, function call, or alias expression is placed on its own line followed by a trailing comma. This makes adding, removing, or reordering columns in version control straightforward and clean.
Explicit Join Indentation
Every JOIN operator starts on a new line indented relative to the FROM clause, with the ON predicate condition aligned directly beside or under the joined table reference.
Parenthetical Subquery Block Alignment
Opening parentheses for multi-line subqueries or CTE definitions start on the initiating line or a new line, with the internal query indented by 2 or 4 spaces. The closing parenthesis aligns with the opening clause margin.
5. Step-by-Step Tutorial
Follow this 6-step walkthrough to format, clean, and audit your SQL database queries:
1Paste Raw or Unformatted SQL Text
Copy raw SQL text from your application source code, log file, ORM console output, or database management tool (SSMS, DBeaver, pgAdmin) and paste it into the left Input Editor pane.
2Configure Formatting & Dialect Options
Select your target SQL dialect (PostgreSQL, MySQL, Standard SQL, Transact-SQL, SQLite, MariaDB) and set keyword capitalization preferences (UPPERCASE or lowercase) using the options header.
3Click Beautify / Format SQL
Click the Beautify button to execute client-side tokenization. The formatted SQL query renders instantly in the right Result Editor pane.
4Review Formatted Output & Subquery Nesting
Inspect the color-coded output. Verify that table joins, WHERE predicate conditions, column projections, and nested subqueries are properly aligned.
5Copy Formatted Output to Clipboard
Click the Copy button to copy the formatted, production-ready SQL string to your clipboard for use in pull requests, migration files, or documentation.
6Client-Side Execution & Privacy Guarantee
All parsing and formatting runs 100% inside your browser's V8 JavaScript engine. Your queries, table schemas, and inline data values are never uploaded to any remote server.
6. Practical Query Examples
Examine real-world query formatting transformations across major SQL statement categories, including SELECT, INSERT, UPDATE, DELETE, GROUP BY, CTEs, and Window Functions:
1. SELECT Statement with Multiple JOINs & Conditions
SELECT & JOINsUnformatted single-line SELECT query with mixed keyword casing, multiple INNER and LEFT JOINs, and complex WHERE conditions.
select u.id,u.email,p.first_name,p.last_name,o.total_amount from users u inner join profiles p on u.id=p.user_id left join orders o on u.id=o.user_id where u.status='active' and o.created_at>='2026-01-01' order by o.created_at desc
SELECT u.id, u.email, p.first_name, p.last_name, o.total_amount FROM users u INNER JOIN profiles p ON u.id = p.user_id LEFT JOIN orders o ON u.id = o.user_id WHERE u.status = 'active' AND o.created_at >= '2026-01-01' ORDER BY o.created_at DESC;
2. INSERT Statement with Multiple Columns & Values
INSERT StatementsRaw, unformatted INSERT statement containing a long column list and multi-row payload.
insert into audit_logs (event_type,user_id,ip_address,created_at,metadata) values ('LOGIN',1042,'192.168.1.1',NOW(),'{"browser":"Chrome"}'),('LOGOUT',1042,'192.168.1.1',NOW(),'{}')INSERT INTO
audit_logs (
event_type,
user_id,
ip_address,
created_at,
metadata
)
VALUES
(
'LOGIN',
1042,
'192.168.1.1',
NOW(),
'{"browser":"Chrome"}'
),
(
'LOGOUT',
1042,
'192.168.1.1',
NOW(),
'{}'
);3. UPDATE Statement with SET Clauses & Subquery
UPDATE StatementsCompressed UPDATE statement modifying multiple columns based on a conditional subquery.
update account_balances set balance=balance-150.00,updated_at=NOW(),status=case when balance-150.00<0 then 'overdrawn' else 'active' end where account_id in (select account_id from pending_transfers where status='approved')
UPDATE
account_balances
SET
balance = balance - 150.00,
updated_at = NOW(),
status = CASE
WHEN balance - 150.00 < 0 THEN 'overdrawn'
ELSE 'active'
END
WHERE
account_id IN (
SELECT
account_id
FROM
pending_transfers
WHERE
status = 'approved'
);4. DELETE Statement with Multi-Condition WHERE Clause
DELETE StatementsMulti-condition DELETE query with timestamp filtering and status checks.
delete from user_sessions where expired_at<NOW() or (is_active=false and last_ping<'2026-06-01')
DELETE FROM
user_sessions
WHERE
expired_at < NOW()
OR (
is_active = false
AND last_ping < '2026-06-01'
);5. Aggregation Query with GROUP BY & HAVING Clauses
GROUP BY & HAVINGAnalytical aggregation query calculating total revenue and order counts per customer category.
select c.category_name,count(o.id) as total_orders,sum(o.total_amount) as total_revenue from customers c join orders o on c.id=o.customer_id group by c.category_name having count(o.id)>=10 and sum(o.total_amount)>5000.00 order by total_revenue desc
SELECT c.category_name, COUNT(o.id) AS total_orders, SUM(o.total_amount) AS total_revenue FROM customers c JOIN orders o ON c.id = o.customer_id GROUP BY c.category_name HAVING COUNT(o.id) >= 10 AND SUM(o.total_amount) > 5000.00 ORDER BY total_revenue DESC;
6. Common Table Expression (CTE / WITH Clause)
CTEs & SubqueriesComplex multi-CTE query preparing regional sales summaries prior to final join selection.
with regional_sales as (select region_id,sum(amount) as total_sales from sales group by region_id),top_regions as (select region_id from regional_sales where total_sales>100000) select r.name,rs.total_sales from regions r join regional_sales rs on r.id=rs.region_id where r.id in (select region_id from top_regions)
WITH
regional_sales AS (
SELECT
region_id,
SUM(amount) AS total_sales
FROM
sales
GROUP BY
region_id
),
top_regions AS (
SELECT
region_id
FROM
regional_sales
WHERE
total_sales > 100000
)
SELECT
r.name,
rs.total_sales
FROM
regions r
JOIN regional_sales rs ON r.id = rs.region_id
WHERE
r.id IN (
SELECT
region_id
FROM
top_regions
);7. Window Functions (OVER, PARTITION BY, DENSE_RANK)
Window FunctionsAnalytical query utilizing window ranking functions over partitioned customer partitions.
select employee_id,department_id,salary,dense_rank() over (partition by department_id order by salary desc) as salary_rank from employees
SELECT
employee_id,
department_id,
salary,
DENSE_RANK() OVER (
PARTITION BY
department_id
ORDER BY
salary DESC
) AS salary_rank
FROM
employees;7. Production Code Implementations
Complete, working code snippets for programmatic SQL formatting in JavaScript, TypeScript, Node.js, and Python.
JavaScript / Node.js (`sql-formatter` open-source library)
Using the `sql-formatter` npm package to format SQL queries programmatically with custom dialect and indentation options.
import { format } from 'sql-formatter';
const rawSql = "select u.id,u.name,o.total from users u join orders o on u.id=o.user_id where u.active=1";
const formattedSql = format(rawSql, {
language: 'postgresql', // Supports 'postgresql', 'mysql', 'transactsql', 'sqlite', 'plsql'
keywordCase: 'upper', // 'upper' | 'lower' | 'preserve'
tabWidth: 2, // Number of spaces for indentation
useTabs: false,
linesBetweenQueries: 2
});
console.log(formattedSql);
/* Output:
SELECT
u.id,
u.name,
o.total
FROM
users u
JOIN orders o ON u.id = o.user_id
WHERE
u.active = 1;
*/TypeScript (Strongly Typed SQL Formatting Helper)
Type-safe wrapper function for formatting SQL queries in TypeScript application backends and ORM logging hooks.
import { format, SqlLanguage } from 'sql-formatter';
export interface SqlFormatOptions {
dialect?: SqlLanguage;
uppercaseKeywords?: boolean;
indentSpaces?: number;
}
export function formatSqlQuery(sql: string, options: SqlFormatOptions = {}): string {
const { dialect = 'postgresql', uppercaseKeywords = true, indentSpaces = 2 } = options;
if (!sql || typeof sql !== 'string') return '';
return format(sql, {
language: dialect,
keywordCase: uppercaseKeywords ? 'upper' : 'preserve',
tabWidth: indentSpaces,
});
}Python (`sqlparse` library implementation)
Using Python's `sqlparse` library to reformat and beautify SQL strings inside Django/FastAPI backend logging or CLI tools.
import sqlparse
raw_sql = "select id,name,email from users where status='active' order by created_at desc"
formatted_sql = sqlparse.format(
raw_sql,
reindent=True,
keyword_case='upper',
indent_width=2,
strip_comments=False
)
print(formatted_sql)
# Output:
# SELECT id,
# name,
# email
# FROM users
# WHERE status='active'
# ORDER BY created_at DESC;8. Common Formatting Problems & Fixes
1. Mixed Keyword Casing in Legacy Scripts
Legacy database scripts often combine uppercase (SELECT), lowercase (from), and camelCase (Where) keywords. The formatter scans the token stream and converts all unquoted SQL keywords to consistent uppercase.
2. Missing Parentheses in Complex Predicates
Unformatted queries combining AND and OR operators without clear parentheses lead to operator precedence bugs. Formatting isolates parenthetical groups onto separate indented lines, exposing logical evaluation precedence.
3. Monolithic Single-Line Query Strings
ORM log outputs and backend query builders generate compressed, 500-character single-line SQL strings that are impossible to inspect. The formatter inserts line breaks before every major clause keyword, transforming walls of text into structured multi-line queries.
4. Dialect-Specific Quotation Collisions
Using MySQL backtick quotes (`table`) in PostgreSQL or double quotes ("table") in MySQL produces syntax errors. Setting the correct dialect in ToolMono SQL Formatter preserves native quotation semantics without corrupting identifiers.
9. Edge Cases & Complex Constructs
CREATE TABLE or INSERT statements are processed sequentially, with mandatory line breaks inserted between individual query statements.WITH RECURSIVE cte AS (...)) contain self-referential UNION ALL branches. The formatter indents both the initial anchor query and the recursive query branch uniformly."select" or `order`), the lexer identifies the surrounding quotes and treats it as a column identifier rather than a query keyword.BEGIN, END, DECLARE, IF ... THEN ... END IF) are formatted with nested block indentation matching procedural scope depth.10. Performance & Client-Side Execution
ToolMono SQL Formatter operates entirely inside your web browser. Its high-performance lexical tokenizer processes text in linear time $O(N)$ relative to input length:
- Instant Execution: Queries up to 10,000 characters (several hundred lines of SQL) format in under 5 milliseconds in V8 memory.
- Zero Network Overhead: Because formatting occurs locally in JavaScript, there are no HTTP request latencies, network timeouts, or server queue delays.
- Memory Management: Temporary AST token nodes are garbage-collected immediately after serialization, keeping browser memory footprint under 2 MB even during large script operations.
- Offline Usability: Once loaded, the formatter works completely offline without requiring an active internet connection.
11. SQL Formatting Best Practices
1. Capitalize All SQL Keywords
Always write keywords in UPPERCASE (SELECT, FROM, WHERE, JOIN) to maintain clear visual separation between SQL commands and schema identifiers.
2. Format One Column Per Line
In SELECT list projections, place each column on its own line. This simplifies Git diff auditing when columns are added or removed during schema updates.
3. Use Meaningful Table Aliases
Use short, clear table aliases (e.g., u for users, o for orders) rather than non-descriptive names like t1 or t2.
4. Format Generated SQL Before Debugging
When debugging raw SQL extracted from ORM logs (Hibernate, Prisma, TypeORM, SQLAlchemy), run the query through ToolMono SQL Formatter before analyzing execution plans.
12. Frequently Asked Questions
13. Authoritative Specifications & References
ISO/IEC 9075: Information Technology Database Language SQL
International ISO standard specification for ANSI SQL syntax.
PostgreSQL Documentation: SQL Commands
Official PostgreSQL language reference and query formatting standards.
MySQL 8.0 Reference Manual: SQL Statement Syntax
Official MySQL documentation for SQL dialect statements.