Up and running in minutes

Install sqltgen, write a schema and a couple of annotated queries, configure your target language, and run the generator. This walkthrough uses PostgreSQL and Rust — swap in any dialect or language you like.

01 Install sqltgen

The quickest way — no install required:

$ docker run --rm -v $(pwd):/workspace sqltgen/sqltgen generate --config sqltgen.json

Or build from source with Rust:

$ git clone https://github.com/sqltgen/sqltgen
$ cd sqltgen/sqltgen
$ cargo build --release

See the installation guide for all options including Homebrew and pre-built binaries.


02 Write your schema

Create a schema.sql file (or a migrations/ directory of numbered files). sqltgen reads DDL to infer column types for your generated code.

-- schema.sql

CREATE TABLE users (
    id         bigserial    PRIMARY KEY,
    name       text         NOT NULL,
    email      text         NOT NULL UNIQUE,
    bio        text,
    created_at timestamptz  NOT NULL DEFAULT now()
);

sqltgen supports CREATE TABLE, ALTER TABLE, DROP TABLE, CREATE VIEW, and migration directories. Column types are mapped to idiomatic language types automatically.


03 Annotate your queries

Add a -- name: FunctionName :command comment above each SQL statement. Use @param_name for parameters — sqltgen infers their types from the schema and rewrites them to the correct dialect placeholder ($1, ?1, etc.).

-- queries.sql

-- name: CreateUser :one
INSERT INTO users (name, email)
VALUES (@name, @email)
RETURNING *;

-- name: GetUser :one
SELECT id, name, email, bio, created_at
FROM   users
WHERE  id = @id;

-- name: ListUsers :many
SELECT id, name, email, bio, created_at
FROM   users
ORDER BY name;

-- name: UpdateBio :one
-- @bio null
UPDATE users
SET    bio = @bio
WHERE  id  = @id
RETURNING id, name, bio;

-- name: DeleteUser :exec
DELETE FROM users
WHERE  id = @id;

Available commands:

Command Returns Rust example Java example
:one Single optional row Option<T> Optional<T>
:many All rows Vec<T> List<T>
:exec Nothing () void
:execrows Affected-row count u64 long

04 Create sqltgen.json

Create a sqltgen.json file in your project root. Point it at your schema and queries, and configure one or more output languages.

{
  "version": "1",
  "engine":  "postgresql",
  "schema":  "schema.sql",
  "queries": "queries.sql",
  "gen": {
    "rust": { "out": "src/db" }
  }
}

The "engine" field accepts "postgresql", "sqlite", or "mysql". You can add multiple languages to the "gen" object and sqltgen will emit code for all of them in one run.

// Generate Rust, Java, and TypeScript in one pass:
"gen": {
  "rust":       { "out": "src/db" },
  "java":       { "out": "gen", "package": "com.example.db" },
  "typescript": { "out": "src/db" }
}

05 Run the generator

Run sqltgen generate from your project root. It reads sqltgen.json by default, or pass an explicit path with --config.

$ sqltgen generate
Generated src/db/users.rs
Generated src/db/queries.rs
Generated src/db/querier.rs
Generated src/db/_sqltgen.rs
Generated src/db/mod.rs

06 Use the generated code

Import the generated module and call the typed query functions directly, or use the Querier wrapper that holds your connection pool.

// main.rs
use db::querier::Querier;
use db::queries::{get_user, create_user};

let q = Querier::new(pool.clone());

// Via the Querier wrapper
let user = q.get_user(42).await?;

// Or call the free function directly
let new_user = create_user(
    &pool, "Alice", "alice@example.com"
).await?;

The Querier struct is the primary API for query execution — it owns a reference to your connection pool and delegates to the generated free functions. All generated functions are async (in Rust), typed to your exact schema, and have no hidden runtime overhead.


Next steps

This covered the basics. The full documentation goes deeper: