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 number

Global flags#

FlagDescription
-f, --fileAlternate config file (default: sqlc.yaml)
--remoteEnable remote execution via sqlc.cloud
--no-remoteDisable remote execution

Per-command flags#

CommandFlagDescription
init--v1 / --v2Generate v1 or v2 config (mutually exclusive; v2 default)
parse-d, --dialectSQL dialect: postgresql, mysql, sqlite, clickhouse
push-t, --tagTag this push with one or more values
push--dry-runDump push request without uploading
verify--againstCompare against a specific tag (default: latest)
createdb--querysetName 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.
  • SQLCDEBUG env var controls debug sub-flags (e.g., trace=<path>, processplugins=0, databases=managed).
  • SQLCEXPERIMENT env 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:

TransportMechanismUse case
In-processext.HandleFunc wrapping a Go functionBuilt-in generators (Go, JSON)
WASMwasm.Runner via WazeroHermetic sandboxed plugins
Processprocess.Runner subprocess, proto on stdin/stdoutExternal 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 config
  • catalog — 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 binary
  • plugin_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 with cmd tag (:one, :many, :exec, :copyfrom, etc.), typed column list, typed parameter list
  • Column — includes type identifier, nullability, array info, scope, table reference
  • Catalog / 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-binary

Plugin 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) int

Run 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
  GetQuerySets

No 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:

VariableTypeDescription
queryvet.QueryThe query being checked (sql, name, cmd, params)
configvet.ConfigThe queryset config (version, engine, schema, queries)
postgresqlvet.PostgreSQLEXPLAIN ANALYZE output (when DB connected)
mysqlvet.MySQLEXPLAIN 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:

  1. 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).

  2. Plugin authors — implement the protobuf CodegenService.Generate RPC, receiving a typed query IR and returning output files. Can use any language; WASM is the recommended delivery mechanism for portability and sandboxing.

  3. 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.