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 sqlformat
Or 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
.