10 languages, 56 backends
Rust, Python, TypeScript, Go, Java, Kotlin, C#, Elixir, Ruby, PHP – plus plain JavaScript via the TypeScript backends’ JSDoc emit mode.
Polyglot SQL-to-code generator with built-in linting and formatting.
Write SQL. Get type-safe code. In any language.
10 languages, 56 backends
Rust, Python, TypeScript, Go, Java, Kotlin, C#, Elixir, Ruby, PHP – plus plain JavaScript via the TypeScript backends’ JSDoc emit mode.
10 databases
PostgreSQL, MySQL, MariaDB, SQLite, DuckDB, CockroachDB, Redshift, SQL Server, Oracle, Snowflake.
58 built-in rules
23 lint + 35 audit rules – plus sqruff’s 69 style rules – catch bugs before they ship.
scythe check adds 8 provenance and 7 schema drift rules on top.
Smart type inference
Nullability from JOINs, COALESCE, window functions, and aggregates.
Configurable row types
Pydantic, msgspec, Zod, or language defaults per backend.
@optional parameters
SQL rewriting for conditional filters without dynamic query building.
cargo install scythe-cli# orbrew install Goldziher/tap/scythe# or, with no Rust toolchain:npm install --save-dev scythe-clipip install scythe-sql-- @name GetUserOrders-- @returns :manySELECT u.id, u.name, o.total, o.notesFROM users uLEFT JOIN orders o ON u.id = o.user_idWHERE u.status = $1;Scythe knows o.total and o.notes are nullable (right side of LEFT JOIN) and generates type-safe code:
pub struct GetUserOrdersRow { pub id: i32, pub name: String, pub total: Option<rust_decimal::Decimal>, pub notes: Option<String>,}@dataclassclass GetUserOrdersRow: id: int name: str total: decimal.Decimal | None notes: str | Noneinterface GetUserOrdersRow { id: number; name: string; total: string | null; notes: string | null;}type GetUserOrdersRow struct { Id int32 `json:"id"` Name string `json:"name"` Total *decimal.Decimal `json:"total"` Notes *string `json:"notes"`}public record GetUserOrdersRow( int id, String name, @Nullable BigDecimal total, @Nullable String notes) {}data class GetUserOrdersRow( val id: Int, val name: String, val total: java.math.BigDecimal?, val notes: String?,)public record GetUserOrdersRow( int Id, string Name, decimal? Total, string? Notes);defmodule GetUserOrdersRow do @type t :: %__MODULE__{ id: integer(), name: String.t(), total: Decimal.t() | nil, notes: String.t() | nil } defstruct [:id, :name, :total, :notes]endmodule Queries GetUserOrdersRow = Data.define( :id, :name, :total, :notes )endreadonly class GetUserOrdersRow { public function __construct( public int $id, public string $name, public ?string $total, public ?string $notes, ) {}}