Overview

Three Categories of SQL Tooling#

SQL files compiled to typed code — scythe, sqlc, SQLDelight, PgTyped, aiosql, PugSQL, HugSQL, and Yesql all start from SQL files you write. Scythe takes the static route, so generation needs no database connection at all, unlike PgTyped, which requires a running Postgres instance to introspect types.

Verified against a live database — sqlx, PgTyped, and SafeQL verify types by talking to a live database at build or generation time. Live-database checking is authoritative about column types; static analysis is not, and a parser lagging a dialect update can be confidently wrong. Scythe's static analysis can optionally add this layer with scythe check --database-url, without requiring it for every generation.

Schema-first code generation — jOOQ, go-jet, SQLBoiler, Kysely, and Prisma generate query builders from an introspected schema rather than from SQL files you author directly.

vs sqlc#

sqlc primarily targets Go, with community plugins for Python, Kotlin, and TypeScript. Scythe supports 10 languages as first-class backends and includes SQL linting (59 rules) plus better nullability inference through JOINs and aggregate functions. If you're migrating an existing sqlc project, scythe migrate sqlc.yaml converts your config and query annotations automatically — see Migrating from sqlc.

vs SQLDelight#

SQLDelight generates Kotlin only (JVM, Native, and JS via Kotlin Multiplatform), requires Gradle, and offers reactive query support through Kotlin Flow. Scythe generates 10 languages from the same SQL source, at the cost of not offering SQLDelight's Flow-based reactivity.

vs jOOQ#

jOOQ uses a Java/Kotlin fluent API to build SQL at runtime, which enables dynamic query composition. Scythe uses plain SQL files, and scythe queries are static — the SQL you write is the SQL that runs, with no runtime query-building layer.

vs ORMs#

The general trade-offs
  • N+1 queries — ORMs suffer from lazy loading; with scythe, you write the JOIN yourself, so it's one query, one round trip.
  • Opaque SQL — the SQL you write is the SQL that runs, versus the SQL an ORM generates on your behalf.
  • Type safety — scythe does static analysis with precise nullability inference; ORMs typically struggle to type aggregations and outer joins correctly.
Hibernate (Java/Kotlin)

Hibernate's session cache and lazy-loading proxies solve object-graph problems scythe doesn't attempt to solve — scythe has no notion of an object graph, only rows. If your Java/Kotlin app needs dirty-checking and cascading saves across an entity graph, Hibernate remains the better fit; if it needs precise, fast SQL, generate it with the Java backend.

SQLAlchemy (Python)

SQLAlchemy Core gives you a query builder with database portability; the ORM layer on top adds session management and unit-of-work semantics. Scythe's Python backend skips both layers and returns dataclass, pydantic, or msgspec rows directly from hand-written SQL.

ActiveRecord (Ruby)

ActiveRecord's convention-over-configuration model is fast to prototype with. Scythe trades that speed for explicit SQL and generated Data.define row types — a fit once query performance and schema drift start to matter more than migration speed.

Entity Framework (C#)

EF's LINQ-to-SQL translation is powerful but its generated SQL is opaque and sometimes surprising under complex joins. Scythe's C# backend generates from SQL you wrote and reviewed yourself.

GORM (Go)

GORM's struct-tag-driven queries are convenient for CRUD but push complex joins into raw SQL strings anyway. Scythe's go-pgx and go-database-sql backends give you typed functions for that same raw SQL from the start.

Diesel (Rust)

Diesel's compile-time query DSL is itself a form of static SQL safety, closer in spirit to scythe than to a typical ORM. The difference is surface: Diesel encodes queries in Rust syntax; scythe encodes them in SQL and generates the Rust.

Ecto (Elixir)

Ecto's changesets and schema-based queries are idiomatic Elixir. Scythe's elixir-postgrex backend returns tagged-tuple results from hand-written SQL for teams that want the SQL itself to be the source of truth.

Next Steps#

Updated

Was this page helpful?