№ 7 · An explainer for non-engineers
Developer infrastructure

What sqlc is, and why your engineers keep bringing it up.

A small, free tool that quietly removes one of the most tedious, and most bug-prone, parts of building software that talks to a database.

The thirty-second version

Almost every business app needs to read and write to a database. The code that ferries data between the app and the database is repetitive, easy to get wrong, and historically had two bad options: write it by hand (fast but brittle) or hide it behind a heavy framework (safer but slow and opaque).

sqlc is a third option. A developer writes their database queries in plain SQL: the same language a data analyst or DBA already reads, and sqlc automatically generates the matching application code. Bugs that used to slip into production now get caught before the app is even built.

Imagine you run a team that publishes contracts in three languages. Today, every time legal updates the master document, three translators have to redo their versions by hand. They mostly get it right. But sometimes a clause shifts, someone's translation lags by a week, and a customer ends up signing slightly different agreements. You don't notice until something breaks.

That's roughly the situation engineers are in when their application code talks to a database. The database speaks SQL. The application speaks Go, or Python, or TypeScript. Someone has to keep the two in sync, and that someone is usually a developer, doing it by hand, on every change.

sqlc is the auto-translator. The team writes the master document once, in SQL. sqlc produces, and re-produces, every time the SQL changes, perfectly faithful versions in whichever language the app uses. If the master and the translations ever drift, the build fails loudly instead of failing quietly in production.

What it actually does

The mechanics are simple enough to describe without pictures, but pictures help. Here is the entire workflow:

queries.sql -- name: GetUser SELECT * FROM users WHERE id = $1; written by developers sqlc reads the SQL, checks it against the real schema queries.go (or.py.ts) func GetUser(id int) → returns User (typed, checked) generated automatically regenerate whenever the SQL changes INPUT TOOL OUTPUT
A developer writes SQL once. sqlc keeps the application code synchronized, every build, automatically.

The tool runs at build time: meaning, before the application is packaged up and shipped. If the SQL refers to a column that doesn't exist, or expects a number where the database stores text, the build halts and tells the developer exactly where the mismatch is. That same mistake, without sqlc, would typically be discovered by a customer at three in the morning.

Today sqlc generates code for the four most common languages on backend teams, Go, Python, TypeScript, and Kotlin, and supports the three most common databases, PostgreSQL, MySQL, and SQLite.

Why the world needed it

Before sqlc, teams building database-backed software essentially picked between two doors. Both had costs your finance team would recognize.

Door 1

Hand-write everything

  • Fast and transparent: the SQL is right there.
  • But every change needs matching changes in the app code.
  • Typos and mismatches only show up at runtime: i.e. in production.
  • Code reviews are tedious. Bugs are common. Onboarding is slow.
Door 2

Use a heavy framework (an "ORM")

  • The framework hides the SQL behind its own vocabulary.
  • Easier for juniors at first; harder for everyone later.
  • Performance often suffers. Diagnosis is painful.
  • Migrating off the framework later is expensive and risky.
Door 3: sqlc

Real SQL, auto-translated

  • The SQL is the source of truth, readable by anyone.
  • Mismatches caught at build time, not in production.
  • No runtime overhead: the generated code is what a careful human would have written.
  • Walk away anytime: the SQL files are vendor-neutral.

The shift here is small but meaningful. A whole category of work, translating between the database and the app, moves from a thing humans do every day to a thing the build does every build. The humans get that time back. The bugs that come from doing it by hand simply stop appearing.

What it looks like, concretely

You don't need to read code to follow this. The left side is the SQL a developer writes. The right side is what sqlc produces, automatically, on every build. The point is that the right side is no longer something a human has to maintain.

A developer writes this: once
-- name: GetUser:one
SELECT id, name, email
FROM users
WHERE id = $1;
Plain SQL. An analyst or DBA can read it. Lives in a file in the codebase like any other document.
sqlc generates this: every build
// auto-generated; do not edit
func GetUser(id int64) (User, error) {
  //...checked code that runs the query...
}

type User struct {
  ID    int64
  Name  string
  Email string
}
A typed, safe function the app can call. If a column gets renamed in the database tomorrow, this file regenerates, and the build complains anywhere it doesn't fit.

Why it's pretty sweet

For an ops leader, the technical mechanism matters less than the operational consequences. There are six worth knowing.

Whole categories of bugs disappear before launch

Database-mismatch bugs are notorious for slipping past testing and surfacing on a quiet Sunday morning. sqlc catches them at build time, meaning they're impossible to ship. Fewer 3 a.m. pages, fewer customer-facing incidents.

The SQL is readable by the people who care about data

Data analysts, DBAs, compliance officers, and security reviewers can all open one file and see exactly what the application is asking the database to do. No framework vocabulary in the way. Audits get faster. So does cross-team troubleshooting.

Developers spend less time on plumbing

The plumbing code, the most boring, error-prone part of the job, is now generated. Engineers can focus on actual product work. Senior engineers stop reviewing plumbing in pull requests.

It does not lock you in

The SQL files are just SQL. If you ever stop using sqlc, you've lost nothing; the queries are portable. Compare this to heavy frameworks, where leaving the framework is a multi-quarter migration project.

Hiring and onboarding get easier

SQL is one of the most widely taught skills in the industry. New hires, including ones from data backgrounds, can read and contribute to query files on day one, without learning a proprietary framework first.

It is free, open, and mature

MIT-licensed (no cost, no vendor risk), seventeen thousand stars on GitHub, used by serious companies including Mux and Coder, currently on its thirtieth point release. Not a hobby project.

Where it fits, where it doesn't

sqlc fits when your team is building backend services that talk to a relational database (PostgreSQL, MySQL, or SQLite) in Go, Python, TypeScript, or Kotlin. It is less relevant for teams using NoSQL databases, mainframe systems, or buying packaged software rather than building it. If your engineers are asking to adopt it, they are asking for less work and fewer outages, which is generally a good ask to say yes to.