What it is
sqlc generates fully type-safe Go code from your SQL queries. You write .sql files; it produces Go functions with typed parameters and return structs.
Point sqlc at a schema file and a queries file via sqlc.yaml. Each annotated query becomes a Go method with a typed parameter struct and a typed result.
Installation
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latestGetting started
The smallest useful thing you can do with it, and what each part means.
-- query.sql
-- name: GetBook :one
SELECT id, title, year FROM books WHERE id = $1;
-- name: ListBooksByYear :many
SELECT id, title, year FROM books WHERE year > $1 ORDER BY title;queries := db.New(pool)
book, err := queries.GetBook(ctx, 42)
if errors.Is(err, pgx.ErrNoRows) {
return ErrNotFound
}
recent, err := queries.ListBooksByYear(ctx, 1990)
for _, b := range recent {
fmt.Println(b.Title, b.Year) // fields are typed from the schema
}Advanced usage
Where the library earns its place over a simpler alternative.
-- name: CreateOrder :one
INSERT INTO orders (customer_id, total, status)
VALUES ($1, $2, $3)
RETURNING *;Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- column reference is ambiguous
- sqlc validates against the real schema, so it catches this at generation time. Qualify the column with its table name.
- Generated code does not compile after a schema change
- That is the feature working. Run sqlc generate and fix the call sites the compiler now flags.
Best practices
- Commit the generated code so builds do not require sqlc to be installed.
- Regenerate in CI and fail if the output differs — that catches a schema change nobody regenerated for.
- Keep the schema file as the single source of truth, ideally shared with your migration tool.
- Use RETURNING * on inserts so you get the generated ID and defaults back in one round trip.
Background
Why it exists, and what it was reacting to.
Created by Kyle Conroy, sqlc inverts the usual ORM trade-off: instead of hiding SQL behind an abstraction, it reads your schema and queries at build time and generates the mapping code, catching SQL errors before the program runs.
