Skip to content

sqlc

Databases & CachingDatabaseGo

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@latest

Getting started

The smallest useful thing you can do with it, and what each part means.

A query and its generated function
-- 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;
The :one and :many annotations tell sqlc what shape to generate. GetBook returns (Book, error); ListBooksByYear returns ([]Book, error).
Calling the generated code
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
}
There is no reflection and no runtime query building. Rename a column in the schema and regeneration turns every affected call site into a compile error.

Advanced usage

Where the library earns its place over a simpler alternative.

Multi-parameter queries and transactions
-- name: CreateOrder :one
INSERT INTO orders (customer_id, total, status)
VALUES ($1, $2, $3)
RETURNING *;
Multiple parameters generate a named params struct (CreateOrderParams), so call sites cannot silently transpose two arguments of the same type. Pass a transaction to db.New(tx) to run generated queries inside one.

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.