sqlc — API Surface#
API types#
- CLI — primary user-facing interface (
sqlc <command>) - Library — thin public embedding API (
pkg/cli) - Plugin — protobuf-over-stdin/stdout or WASM contract for code generators
- gRPC (internal) — remote execution via sqlc.cloud; quickdb managed database service
CLI#
Framework#
Cobra (github.com/spf13/cobra) with pflag for flag parsing.
Command structure#
sqlc [global flags]
generate Generate source code from SQL
compile Statically check SQL for syntax and type errors
diff Compare the generated files to the existing files
vet Vet examines queries (CEL rules + optional live DB)
verify Verify schema, queries, and configuration (against sqlc.cloud tag)
push Push schema, queries, and config to sqlc.cloud (alias: upload)
createdb Create an ephemeral managed database
parse Parse SQL and output the AST as JSON
init Create an empty sqlc.yaml settings file
version Print the sqlc version numberGlobal flags#
| Flag | Description |
|---|---|
-f, --file | Alternate config file (default: sqlc.yaml) |
--remote | Enable remote execution via sqlc.cloud |
--no-remote | Disable remote execution |
Per-command flags#
| Command | Flag | Description |
|---|---|---|
init | --v1 / --v2 | Generate v1 or v2 config (mutually exclusive; v2 default) |
parse | -d, --dialect | SQL dialect: postgresql, mysql, sqlite, clickhouse |
push | -t, --tag | Tag this push with one or more values |
push | --dry-run | Dump push request without uploading |
verify | --against | Compare against a specific tag (default: latest) |
createdb | --queryset | Name of the queryset to use |
Flag patterns#
- Global flags use
PersistentFlags()on the root command. - Debug and experiment flags are read exclusively from environment variables, not from CLI flags.
SQLCDEBUGenv var controls debug sub-flags (e.g.,trace=<path>,processplugins=0,databases=managed).SQLCEXPERIMENTenv var gates experimental features.
Plugin / Extension system#
This is the most architecturally significant API surface: sqlc’s plugin contract defines how all code generators (built-in or third-party) communicate with the compiler.
Mechanism#
Protobuf over three equivalent transports:
| Transport | Mechanism | Use case |
|---|---|---|
| In-process | ext.HandleFunc wrapping a Go function | Built-in generators (Go, JSON) |
| WASM | wasm.Runner via Wazero | Hermetic sandboxed plugins |
| Process | process.Runner subprocess, proto on stdin/stdout | External language plugins |
All three transports implement grpc.ClientConnInterface, making the codegen dispatch loop a single plugin.NewCodegenServiceClient(handler).Generate(ctx, req) call regardless of transport.
Plugin proto contract (protos/plugin/codegen.proto)#
service CodegenService {
rpc Generate (GenerateRequest) returns (GenerateResponse);
}GenerateRequest — sent by sqlc to the plugin:
settings— engine, version, schema/query file lists, codegen configcatalog— full in-memory schema snapshot (schemas, tables, columns, enums, composite types)queries— typed, named query IR (text, name, cmd, columns, parameters, comments)sqlc_version— semver of the running sqlc binaryplugin_options— raw bytes for plugin-specific config (decoded by the plugin itself)global_options— raw bytes for global config options
GenerateResponse — returned by the plugin to sqlc:
files— list of{name, contents}output files to write to disk
Key IR types:
Query— compiled query withcmdtag (:one,:many,:exec,:copyfrom, etc.), typed column list, typed parameter listColumn— includes type identifier, nullability, array info, scope, table referenceCatalog/Schema/Table— full schema snapshot
Plugin registration (sqlc.yaml)#
plugins:
- name: my-plugin
wasm:
url: https://example.com/my-plugin.wasm
sha256: <hash>
# or:
process:
cmd: my-plugin-binaryPlugin process plugins are disabled by default and require SQLCDEBUG=processplugins=1 (safety measure; process-based plugins were considered less secure than WASM).
Extension points#
Third-party code can hook in only at the codegen stage. There is no hook for:
- The parse/catalog-build phase
- The type-resolution phase
- The vet rule evaluation phase (rules are CEL expressions, not plugins)
Library API (pkg/cli)#
The only public Go package in sqlc. Intentionally minimal.
// package: github.com/sqlc-dev/sqlc/pkg/cli
func Run(args []string) intRun takes CLI args (without os.Args[0]) and returns an exit code. It delegates directly to internal/cmd.Do(args, os.Stdin, os.Stdout, os.Stderr).
API style: Single-function, no options, no configuration structs exposed. The library surface is deliberately kept at one function to allow embedding sqlc in other tools (e.g., sqlc-gen-* plugin scaffolding) without exposing internals.
Backward compatibility: All non-pkg/ packages are internal/, guaranteeing that only Run is a stable public API. No explicit versioning strategy beyond this convention.
gRPC API (internal / sqlc.cloud)#
Remote execution (internal/remote/gen.proto)#
Used when --remote flag or cloud.project config is set. sqlc bundles config + SQL files and sends them to sqlc.cloud instead of running the compiler locally.
service Gen {
rpc Generate(GenerateRequest) returns (GenerateResponse);
}
// GenerateRequest: {version, files[]}
// GenerateResponse: {files[], exit_code, stdout, stderr}Quickdb managed database service (internal/quickdb/v1/)#
Used internally by vet and verify commands when database.managed: true is configured. Communicates with sqlc.cloud to create ephemeral databases for query validation.
QuickService RPCs:
CreateEphemeralDatabase
DropEphemeralDatabase
UploadArchive
VerifyQuerySets
GetQuerySetsNo user-visible HTTP API exists. The gRPC endpoints are exclusively for sqlc-to-sqlc.cloud communication.
Analysis proto (protos/analysis/analysis.proto)#
Defines the column/parameter types returned by the live-database analyzer. Used internally by the internal/analyzer layer; not part of the user-facing plugin contract. Documents the type system used for live-DB column analysis (name, data_type, nullability, array info, scope, table reference).
Vet rules (CEL-based API)#
sqlc vet exposes a domain-specific expression language using Google CEL (Common Expression Language). This is a user-configurable API, not a code API.
Available variables in rule expressions:
| Variable | Type | Description |
|---|---|---|
query | vet.Query | The query being checked (sql, name, cmd, params) |
config | vet.Config | The queryset config (version, engine, schema, queries) |
postgresql | vet.PostgreSQL | EXPLAIN ANALYZE output (when DB connected) |
mysql | vet.MySQL | EXPLAIN FORMAT=JSON output (when DB connected) |
Built-in rule:
sqlc/db-prepare— prepares every query against a live database to verify it is valid SQL (no CEL expression needed; connection required)
Custom rule example (from docs):
rules:
- name: no-pg-seqscan
message: "Query causes a sequential scan"
rule: "postgresql.explain.plan.node_type == 'Seq Scan'"Summary#
sqlc’s API surface has three distinct audiences:
End users — consume the CLI (
generate,compile,diff,vet,verify,push). Rich command set with global and per-command flags. All configuration is file-based (sqlc.yaml).Plugin authors — implement the protobuf
CodegenService.GenerateRPC, receiving a typed query IR and returning output files. Can use any language; WASM is the recommended delivery mechanism for portability and sandboxing.Go tool embedders — call
pkg/cli.Run(args). Single function, stable, deliberately minimal.
The plugin proto contract is the most consequential API design decision: it is the boundary that makes sqlc’s code-generation ecosystem language-agnostic. The narrow Run() library API is a second deliberate choice: sqlc treats its internals as implementation details that can change freely.