Engine plugins let you use sqlc with databases that are not built-in. You can add support for other SQL-compatible systems (e.g. CockroachDB, TiDB, or custom engines) by implementing a small external program that parses SQL and returns parameters and result columns.
- Use sqlc with a database that doesn’t have native support.
- Reuse an existing SQL parser or dialect in a separate binary.
- Keep engine-specific logic outside the sqlc core.
Data returned by the engine plugin (SQL text, parameters, columns) is passed through to codegen plugins without an extra compiler/AST step. The plugin is the single place that defines how queries are interpreted for that engine.
An engine plugin is an external process that implements one RPC:
- Parse — accepts the query text and either schema SQL or connection parameters, and returns processed SQL, parameter list, and result columns.
Process plugins (e.g. written in Go) talk to sqlc over stdin/stdout using Protocol Buffers. The schema is defined in engine/engine.proto.
For Go plugins, compatibility is enforced at compile time by importing the engine package:
import "github.com/sqlc-dev/sqlc/pkg/engine"- If the plugin builds, it matches this version of the engine API.
- If the API changes in a breaking way, the plugin stops compiling until it’s updated.
No version handshake is required; the proto schema defines the contract.
version: "2"
engines:
- name: mydb
process:
cmd: sqlc-engine-mydb
env:
- MYDB_DSN
sql:
- engine: mydb
schema: "schema.sql"
queries: "queries.sql"
codegen:
- plugin: go
out: db| Field | Description |
|---|---|
name |
Engine name used in sql[].engine |
process.cmd |
Command to run (PATH or absolute path) |
env |
Environment variables passed to the plugin |
package main
import "github.com/sqlc-dev/sqlc/pkg/engine"
func main() {
engine.Run(engine.Handler{
PluginName: "mydb",
PluginVersion: "1.0.0",
Parse: handleParse,
})
}The engine API exposes only Parse. There are no separate methods for catalog, keywords, comment syntax, or dialect.
Request
sql— The query text to parse.schema_source— One of:schema_sql: schema as in a schema.sql file (used for schema-based parsing).connection_params: DSN and options for database-only mode.
Response
sql— Processed query text. Often the same as input; with a schema you may expand*into explicit columns.parameters— List of parameters (position/name, type, nullable, array, etc.).columns— List of result columns (name, type, nullable, table/schema if known).
Example handler:
func handleParse(req *engine.ParseRequest) (*engine.ParseResponse, error) {
sql := req.GetSql()
var schema *SchemaInfo
if s := req.GetSchemaSql(); s != "" {
schema = parseSchema(s)
}
// Or use req.GetConnectionParams() for database-only mode.
parameters := extractParameters(sql)
columns := extractColumns(sql, schema)
processedSQL := processSQL(sql, schema) // e.g. expand SELECT *
return &engine.ParseResponse{
Sql: processedSQL,
Parameters: parameters,
Columns: columns,
}, nil
}Parameter and column types use the Parameter and Column messages in engine.proto (name, position, data_type, nullable, is_array, array_dims; for columns, table_name and schema_name are optional).
Support for sqlc placeholders (sqlc.arg(), sqlc.narg(), sqlc.slice(), sqlc.embed()) is up to the plugin: it can parse and map them into parameters (and schema usage) as needed.
go build -o sqlc-engine-mydb .
# Ensure sqlc-engine-mydb is on PATH or use an absolute path in process.cmdProcess plugins use Protocol Buffers on stdin/stdout:
sqlc → stdin (protobuf) → plugin → stdout (protobuf) → sqlc
Invocation:
sqlc-engine-mydb parse # stdin: ParseRequest, stdout: ParseResponseThe definition lives in engine/engine.proto (and generated Go in pkg/engine).
A minimal engine that parses SQLite-style SQL and expands * using a schema is in this repository under examples/plugin-based-codegen/plugins/sqlc-engine-sqlite3/. It pairs with the Rust codegen example in the same plugin-based-codegen sample.
┌─────────────────────────────────────────────────────────────────┐
│ sqlc generate │
│ 1. Read sqlc.yaml, find engine for this sql block │
│ 2. Call plugin: parse (sql + schema_sql or connection_params) │
│ 3. Use returned sql, parameters, columns in codegen │
└─────────────────────────────────────────────────────────────────┘
sqlc sqlc-engine-mydb
│──── spawn, args: ["parse"] ──────────────────────────────► │
│──── stdin: ParseRequest{sql, schema_sql|connection_params} ► │
│◄─── stdout: ParseResponse{sql, parameters, columns} ─────── │
- Codegen plugins — Custom code generators that consume engine output.
- Configuration reference
- Proto schema:
protos/engine/engine.proto