Introduction
sqlc takes a fundamentally different approach to database access. Instead of mapping objects to tables (ORM) or embedding SQL in strings (sqlx), you write plain SQL files and sqlc generates type-safe Go code. Your SQL is the source of truth — sqlc parses it, validates it against your schema, and generates Go structs and functions.
With over 17,000 GitHub stars, sqlc represents the "SQL-first" approach that many Go developers prefer. You get the full power of SQL with compile-time type safety and zero runtime reflection.
What sqlc Does
sqlc reads your SQL schema (CREATE TABLE) and query files, parses them, type-checks them, and generates Go code with properly typed structs for each query result and function parameters. The generated code uses database/sql or pgx — no custom runtime library.
Architecture Overview
[Input Files]
schema.sql — CREATE TABLE statements
query.sql — annotated SQL queries
sqlc.yaml — configuration
|
[sqlc generate]
Parse SQL
Type-check queries against schema
Generate Go code
|
[Generated Go Code]
models.go — structs matching tables
query.sql.go — functions for each query
db.go — Queries interface
|
[Your Application]
Call generated functions
Full type safety
No runtime reflectionSelf-Hosting & Configuration
# sqlc.yaml
version: "2"
sql:
- engine: "postgresql"
queries: "query.sql"
schema: "schema.sql"
gen:
go:
package: "db"
out: "internal/db"
sql_package: "pgx/v5"
emit_json_tags: true
emit_empty_slices: true-- schema.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
bio TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL REFERENCES users(id),
title TEXT NOT NULL,
body TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);// Using generated code
func main() {
ctx := context.Background()
conn, _ := pgx.Connect(ctx, "postgres://localhost/mydb")
queries := db.New(conn)
// Fully typed — compiler catches errors
user, err := queries.CreateUser(ctx, db.CreateUserParams{
Name: "Alice",
Email: "alice@example.com",
})
users, err := queries.ListUsers(ctx)
for _, u := range users {
fmt.Printf("%s (%s)\n", u.Name, u.Email)
}
err = queries.DeleteUser(ctx, user.ID)
}Key Features
- SQL First — write real SQL, not ORM abstractions
- Type Safe — generated Go code with proper types for all queries
- Schema Validation — sqlc validates queries against your schema at generate time
- No Runtime Overhead — generated code uses standard database/sql or pgx
- PostgreSQL & MySQL — full support for both engines
- JSON Tags — auto-generate JSON struct tags for API responses
- Batch Operations — generate code for batch insert and copy
- sqlc Cloud — managed service for query validation and analysis
Comparison with Similar Tools
| Feature | sqlc | GORM | sqlx | Ent | squirrel |
|---|---|---|---|---|---|
| Approach | SQL -> Go code gen | ORM (reflection) | SQL helper | Code-gen ORM | Query builder |
| Type Safety | Compile-time | Runtime | Partial | Compile-time | Runtime |
| SQL Freedom | Full SQL | Limited | Full SQL | Graph queries | Builder pattern |
| Performance | Excellent | Good | Excellent | Very Good | Good |
| Learning Curve | Low (know SQL) | Low (know ORM) | Low | Moderate | Low |
| Migration | Manual / goose | Auto-migrate | Manual | Code-gen | Manual |
FAQ
Q: sqlc vs GORM — which should I use? A: sqlc if you want full SQL control and compile-time safety. GORM for rapid development with auto-migration and associations. sqlc is better for performance-critical and SQL-heavy applications.
Q: Does sqlc support migrations? A: sqlc reads schema files but does not run migrations. Use goose, golang-migrate, or Atlas for migration management. sqlc generates code from your current schema.
Q: Can I use complex PostgreSQL features? A: Yes. sqlc supports CTEs, window functions, JSON operations, array types, custom enums, and most PostgreSQL-specific syntax. It parses real PostgreSQL SQL.
Q: What happens when I change my schema? A: Update your schema.sql, run "sqlc generate" again, and fix any compile errors in your application. The compiler tells you exactly what broke — no runtime surprises.
Sources
- GitHub: https://github.com/sqlc-dev/sqlc
- Documentation: https://docs.sqlc.dev
- Playground: https://play.sqlc.dev
- Created by Kyle Conroy
- License: MIT