# sqlc: type-safe Go, Kotlin, Python and TypeScript from plain SQL queries

> sqlc compiles annotated SQL into typed code instead of mapping objects at runtime. Here is how the compiler works, how to install it, and where it stops being the right tool.

**sqlc-dev/sqlc** — Generate type-safe code from SQL

- Repository: https://github.com/sqlc-dev/sqlc
- Website: https://sqlc.dev
- Stars: 18,336 · Forks: 1,089
- Language: Go
- License: MIT
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/sqlc-dev-sqlc

## The problem sqlc solves: SQL that drifts from the code calling it

Most database access layers in application code sit somewhere between two poles. At one end, a string of SQL is assembled in the application and the driver hands back untyped rows; the column names and argument order live only in the developer's head, and a renamed column fails at runtime. At the other end, a full ORM maps tables to objects and generates the SQL for you, which works until the query you need does not fit the mapping model. sqlc takes a third position. You keep writing SQL by hand, and a compiler reads that SQL together with your schema and emits typed functions. The README states the loop plainly: you write queries in SQL, you run sqlc to generate code with type-safe interfaces to those queries, and you write application code that calls the generated code. The intended user is a team that is comfortable with SQL and wants the compiler, not a runtime library, to catch the mismatch between a query and the code around it. The repository's examples directory contains worked projects for authors, batch, booktest, jets and ondeck, which suggests the maintainers treat runnable examples as part of the project's surface area rather than an afterthought.

## How the compiler works: schema and queries in, typed interfaces out

sqlc is a Go program, and the module path in go.mod is github.com/sqlc-dev/sqlc. Its dependency list is informative about the architecture. The project pulls in github.com/jackc/pgx/v5, github.com/go-sql-driver/mysql and github.com/ncruces/go-sqlite3, which are the drivers it uses to reach the databases it understands, and it also depends on github.com/antlr4-go/antlr/v4, a parser toolkit. That combination points at the actual mechanism: sqlc parses your schema and your query files rather than connecting to a live server to introspect it, and the generated code is produced from that parse. The engine is not only a parser. cel.dev/cel-go appears in the direct dependencies, and sqlc's configuration supports CEL expressions for rules that inspect generated output, so the compiler can be told to reject or rewrite generated code that violates a condition. For languages beyond the four first-party generators, the README points at plugins and a language-support page in the documentation. The remote plugin protocol is visible in the repository too: there is an internal/remote/gen.proto and a Makefile target named remote-proto that regenerates Go bindings from it, and the build depends on google.golang.org/grpc and github.com/riza-io/grpc-go. So a generator can run as a separate process and speak gRPC to the compiler, which is how community languages are added without patching the core. The data flow is therefore: schema files plus annotated query files plus sqlc.yaml in, a parse and type-inference pass, then one or more generators over a plugin boundary, then source files on disk that your build compiles like any other code.

## Installing sqlc and generating your first package

The README does not embed install commands; it links to an installation page under docs.sqlc.dev and to a downloads page at downloads.sqlc.dev, so the canonical instructions live there rather than in the repository root. Because the project is a Go module, the Makefile shows the two build paths the maintainers use themselves: make build runs go build ./..., and make install runs go install ./.... If you have a Go toolchain, the second of those is the shortest route from source to a working binary.

```bash
go install ./...
```

After that, the README's three-step description is the whole workflow. You need a configuration file, a schema, and at least one query file. The configuration names the engine, the schema and query locations, and the output package. The project's own configuration reference and examples are where the full key set is documented; the repository's examples directory holds worked projects for authors, batch, booktest, jets and ondeck that show a complete setup. What you should see after a successful run is a new package containing a struct per query result and a method per query, with parameter types taken from your schema. The maintainers also publish an interactive playground at play.sqlc.dev, which is the cheapest way to see the generated output for a schema and query pair before you commit to the setup locally. If you prefer not to install anything, the repository has a Dockerfile that builds the binary in a golang:1.27.1 stage and copies it into a distroless base image, so an image can be built from the repository as-is.

## Where sqlc stops: dynamic queries, migrations and unparsed SQL

The design has a hard boundary. sqlc generates code for the queries it can see and type-check at compile time. If your application builds filters at runtime, for example a search endpoint where any combination of five optional predicates may be present, there is no single query for the compiler to type. You either write the combinations out as separate named queries or you drop to hand-written SQL for that path, and the second option means the type safety guarantee does not cover it. This is the case where an ORM or a query builder is the better tool, and it is worth being honest about it rather than forcing every access path through the generator. The second boundary is schema input. sqlc reads schema files, and the repository's docker-compose.yml shows the databases the maintainers test against: MySQL, PostgreSQL, Microsoft SQL Server and Spanner Omni, with the Spanner service noted as serving plaintext gRPC on port 15000 and a console on 15026. That is a test matrix, not a promise about your schema. Constructs your database accepts but the parser does not, or migrations whose final state differs from what you feed the compiler, will surface as generation errors or, worse, as generated types that do not match the live database. Feeding sqlc the output of your migration tool, rather than a hand-maintained schema file that has drifted, is the discipline this design demands. The third boundary is language coverage. The README lists first-party generators for Go, Kotlin, Python and TypeScript, and states that additional languages can be added via plugins. If your language is not in that list and has no community generator, adopting sqlc means writing and maintaining a plugin against the gRPC protocol, which is a project in itself.

## sqlc against an ORM: the difference is who owns the SQL

The comparison that matters is with an ORM, and the question to ask is who writes the SQL. An ORM derives statements from object mappings and method chains, and the developer's job is to describe intent in the host language; the SQL is an implementation detail the library chooses, which is convenient until you need a query the mapping cannot express or a plan the generated SQL does not produce. sqlc inverts that. The SQL is the artifact you write and review, and the generator's job is to describe its shape in the host language. That means the query you read in code review is the query that runs, and query plans can be inspected directly. It also means schema changes propagate as compile errors in generated code rather than as runtime failures, which is the main reason teams pick it. The cost is that you give up the ORM's convenience features: no lazy loading of relations, no identity map, no automatic change tracking. You write the join, and you write the insert. For a team that already reviews SQL, that is a fair trade. For a team that chose an ORM precisely to avoid writing SQL, sqlc will feel like a step backwards.

## Maintenance, releases and the MIT licence

The repository is not archived, and the last push was on 2026-09-21. The most recent tagged release is v1.31.1 from 2026-04-22, preceded by v1.31.0 on 2026-04-20 and v1.30.0 on 2025-09-01. The gap between v1.30.0 and v1.31.0 is roughly seven months, and v1.31.1 arrived two days after v1.31.0 as a patch, so the release cadence is not fixed and you should not plan around a predictable minor version every quarter. Upgrading has a specific cost that is easy to underestimate: generated code is checked into many repositories, so a compiler upgrade produces a diff across every generated file. If your build regenerates and diffs in CI, that diff is the upgrade. If you commit generated code and do not regenerate in CI, the compiler version and the committed output can drift silently, and a later upgrade can produce a large, hard-to-review change. Pin the compiler version in your build image and regenerate as part of the build. The project is MIT licensed, with a NOTICE file at the repository root alongside LICENSE. MIT is permissive and imposes no copyleft obligation on your application code, but the generated output and the plugin boundary are areas where your own legal review should look, particularly if you redistribute generated code or write a plugin. Nothing here is legal advice. The README also notes that development is supported by sponsors, which is worth knowing when you weigh how much of your data layer depends on the project.

## Conclusion

Adopt sqlc if your team already writes SQL and wants the database schema, not struct tags, to be the source of truth for generated interfaces in Go, Kotlin, Python or TypeScript. Skip it if you need runtime query building, arbitrary dynamic filters, or a language outside the four supported generators and the plugin ecosystem. Before committing, verify three things on your own schema: that your migrations produce a schema sqlc can parse, that your queries are annotated with the comment markers sqlc needs to infer parameter and result types, and that the generated code survives your CI regeneration check without diffs.

## FAQ

### What does sqlc do?

It generates type-safe code from SQL. You write queries in SQL, run sqlc to generate code with type-safe interfaces to those queries, and then write application code that calls the generated code.

### How do I install sqlc?

The README links to an installation page under docs.sqlc.dev and to downloads.sqlc.dev rather than embedding commands. From a cloned repository with a Go toolchain, the Makefile's install target runs go install ./....

### Is sqlc an ORM?

No. An ORM derives SQL from object mappings, while sqlc takes SQL you wrote yourself and generates typed interfaces to it. There is no runtime mapping layer, so features like lazy loading and change tracking are not part of the model.

## Sources

- [License: MIT](https://github.com/sqlc-dev/sqlc/blob/main/LICENSE)
- [Project website](https://sqlc.dev)
- [README](https://github.com/sqlc-dev/sqlc/blob/main/README.md)
- [Releases](https://github.com/sqlc-dev/sqlc/releases)
- [sqlc-dev/sqlc on GitHub](https://github.com/sqlc-dev/sqlc)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sqlc-dev-sqlc
