Format SQL strings into readable, consistently styled output. sqlformat is a pure-Rust library designed to pretty-print SQL from a variety of mainstream dialects, ideal for logging, debugging, tests, or developer tools.
This crate is a Rust port of sql-formatter-plus. There is currently no binary; the crate is intended to be used as a library.
- Broad SQL support: Common constructs from PostgreSQL, MySQL/MariaDB, SQLite, SQL Server, and Oracle (DDL, DML, CTEs, CASE, JOINs, window functions, operators, type casts, etc.).
- Configurable style: Indentation (spaces or tabs), upper/lower/preserve keyword case, control lines between statements.
- Inline controls: Keep short blocks or argument lists inline when they fit; split when they don’t.
- Parameter interpolation: Supports
?,?1,$1,$name,:name,@name, and bracketed variants viaQueryParams. - Comment-aware: Respects line/block comments; supports in-query toggles to temporarily disable formatting.
- Safe Rust:
#![forbid(unsafe_code)].
use sqlformat::{format, FormatOptions, Indent, QueryParams};
fn main() {
let sql = "SELECT id, name FROM users WHERE created_at > NOW();";
let options = FormatOptions::default();
let formatted = format(sql, &QueryParams::None, &options);
println!("{}", formatted);
}Output:
SELECT
id,
name
FROM
users
WHERE
created_at > NOW();
Add via Cargo:
cargo add sqlformatOr manually in Cargo.toml:
[dependencies]
sqlformat = "*"Minimum Supported Rust Version (MSRV): 1.84.
use sqlformat::{format, FormatOptions, QueryParams};
let sql = "SELECT count(*), col FROM t WHERE a = 1 AND b = 2;";
let out = format(sql, &QueryParams::None, &FormatOptions::default());use sqlformat::{format, FormatOptions, Indent, QueryParams};
let options = FormatOptions { indent: Indent::Spaces(4), ..Default::default() };
let out = format("SELECT a, b FROM t;", &QueryParams::None, &options);
let options = FormatOptions { indent: Indent::Tabs, ..Default::default() };
let out = format("SELECT a, b FROM t;", &QueryParams::None, &options);use sqlformat::{format, FormatOptions, QueryParams};
// Uppercase reserved keywords
let options = FormatOptions { uppercase: Some(true), ..Default::default() };
let out = format("select distinct * from foo where bar = 1", &QueryParams::None, &options);
// Lowercase reserved keywords
let options = FormatOptions { uppercase: Some(false), ..Default::default() };
let out = format("SELECT DISTINCT * FROM FOO WHERE BAR = 1", &QueryParams::None, &options);
// Preserve case with exceptions
let options = FormatOptions {
uppercase: Some(true),
ignore_case_convert: Some(vec!["from", "where"]),
..Default::default()
};
let out = format("select * from foo where bar = 1", &QueryParams::None, &options);Control how aggressively short blocks and argument lists are kept on one line.
use sqlformat::{format, FormatOptions, QueryParams};
let options = FormatOptions {
inline: false, // when true, forces single-line output
max_inline_block: 50, // characters allowed to keep a parenthesized block inline
max_inline_arguments: Some(40),
max_inline_top_level: Some(40),
..Default::default()
};
let out = format("SELECT a, b, c, d, e, f, g, h FROM t;", &QueryParams::None, &options);Treat any JOIN as a top-level keyword (affects line breaks):
use sqlformat::{format, FormatOptions, QueryParams};
let options = FormatOptions { joins_as_top_level: true, ..Default::default() };
let out = format("SELECT * FROM a INNER JOIN b ON a.id = b.a_id", &QueryParams::None, &options);sqlformat can substitute placeholders using QueryParams:
use sqlformat::{format, FormatOptions, QueryParams};
// Numbered / positional (e.g., ?, ?1, $1)
let sql = "SELECT ?1, ?, $2;";
let params = QueryParams::Indexed(vec!["first".to_string(), "second".to_string(), "third".to_string()]);
let out = format(sql, ¶ms, &FormatOptions::default());
// Named (e.g., $name, :name, @name, :\"weird name\")
let sql = "SELECT $hash, :name, @`var name`;";
let params = QueryParams::Named(vec![
("hash".to_string(), "hash value".to_string()),
("name".to_string(), "Alice".to_string()),
("var name".to_string(), "Bob".to_string()),
]);
let out = format(sql, ¶ms, &FormatOptions::default());use sqlformat::{format, FormatOptions, QueryParams};
let options = FormatOptions { lines_between_queries: 2, ..Default::default() };
let out = format("SELECT 1; SELECT 2;", &QueryParams::None, &options);You can turn formatting off/on using SQL comments. This is helpful when you want to preserve a very specific layout.
-- fmt: off
SELECT * FROM t WHERE a=1 AND b=2; -- preserved as-is
-- fmt: on
/* fmt: off */ SELECT 1 + 2; /* fmt: on */The formatter is configured through FormatOptions. See the full API on the docs site for list of options.
- Crate docs:
docs.rs/sqlformat - Primary entry point:
format(query: &str, params: &QueryParams, options: &FormatOptions) -> String
Contributions are welcome!
- Run tests:
cargo test - Run benchmarks (optional):
cargo bench
Please open issues and pull requests with clear descriptions and examples. Bug reports that include an input SQL snippet, your FormatOptions, and the actual vs. expected output are especially helpful.
Dual-licensed under either of:
- MIT License (
LICENSE-MIT) - Apache License, Version 2.0 (
LICENSE-APACHE)
Based on the excellent work in sql-formatter-plus.