Configuration

sqltgen is configured by a JSON file, sqltgen.json by default.

sqltgen generate                          # reads sqltgen.json in the current directory
sqltgen generate --config path/to/sqltgen.json
sqltgen generate -c path/to/sqltgen.json

Full reference

{
  "version": "1",
  "engine": "postgresql",
  "schema": "migrations/",
  "queries": "queries.sql",
  "gen": {
    "java":       { "out": "src/main/java",   "package": "com.example.db" },
    "kotlin":     { "out": "src/main/kotlin", "package": "com.example.db" },
    "rust":       { "out": "src/db",          "package": "" },
    "python":     { "out": "gen",             "package": "" },
    "typescript": { "out": "src/db",          "package": "" },
    "javascript": { "out": "src/db",          "package": "" }
  }
}

Top-level fields

FieldRequiredDescription
versionyesMust be "1".
engineyesSQL dialect. One of "postgresql", "sqlite", "mysql".
schemayesPath to a .sql file or a directory. See Schema path.
schema_stop_markernoStrip down-migration sections. See Migration files with up/down sections.
default_schemanoDefault schema for unqualified table references. See Default schema.
queriesyesQuery source(s). See Queries field.
genyesMap of language key → output config. At least one entry required.

Schema path

The schema field accepts:

  • A single file"schema.sql".

  • A directory — all .sql files in the directory are loaded in lexicographic order. This is ideal for numbered migration files:

    migrations/
      001_create_users.sql
      002_create_posts.sql
      003_add_tags.sql
    
    "schema": "migrations/"
    

    sqltgen applies CREATE TABLE, ALTER TABLE, and DROP TABLE in file order, so the final schema reflects the fully-migrated state.

Statements sqltgen does not recognise (CREATE INDEX, CREATE FUNCTION, etc.) are silently skipped.

Migration files with up/down sections

Some migration tools (dbmate, goose, golang-migrate) store both the "up" and "down" SQL in a single file, separated by a comment marker:

-- migrate:up
CREATE TABLE users (id BIGINT PRIMARY KEY, name TEXT NOT NULL);

-- migrate:down
DROP TABLE users;

Set schema_stop_marker to the down-section marker and sqltgen will discard everything from that line onward in each file:

{
  "schema": "migrations/",
  "schema_stop_marker": "-- migrate:down"
}

Common values by tool:

Toolschema_stop_marker
dbmate"-- migrate:down"
goose"-- +goose Down"
golang-migrate / sql-migrate"-- +migrate Down"

Omit the field (or set it to null) to read files in full — this is the default and preserves existing behaviour.

Default schema

When your DDL uses schema-qualified table names (e.g. CREATE TABLE public.users), unqualified references in queries (e.g. SELECT * FROM users) need to know which schema to match against. Set default_schema to control this:

{
  "engine": "postgresql",
  "default_schema": "public"
}

If omitted, sqltgen uses the engine's conventional default:

EngineDefault
postgresql"public"
sqlite"main"
mysqlnone (schema = database; specify explicitly if needed)

This also applies to DDL operations: ALTER TABLE users will match public.users when the default schema is "public".

Most projects can omit this field entirely. Set it only if your DDL uses a non-standard schema (e.g. a custom PostgreSQL search_path).

Queries field

The queries field accepts three forms.

Single file

All queries land in one output file per language (Queries.java, queries.ts, etc.):

"queries": "queries.sql"

Array of paths or globs

Each file becomes its own group, named after the file stem. users.sql → group usersUsersQueries.java / users.ts.

"queries": ["queries/users.sql", "queries/posts.sql"]

Glob patterns are supported and are sorted lexicographically:

"queries": ["queries/**/*.sql"]

An error is raised if a glob matches no files.

Grouped map

Full control over group names and which files belong to each group. Values can be a single path/glob or an array:

"queries": {
  "users": "queries/users.sql",
  "posts": ["queries/posts/**/*.sql", "queries/extra.sql"]
}

Output file names per group

Group nameJava / KotlinRust / Python / TypeScript / JavaScript
usersUsersQueries.java / .ktusers.rs / users.py / users.ts / users.js
postsPostsQueries.java / .ktposts.rs / posts.py / posts.ts / posts.js
(single file)Queries.java / .ktqueries.rs / queries.py / queries.ts / queries.js

Per-language output config (gen.*)

FieldRequiredDescription
outyesOutput root directory. Generated files are written under this path.
packageyesPackage or module name. Empty string "" for languages without packages (Rust, Python, TypeScript, JavaScript). For Java/Kotlin: "com.example.db".
list_paramsnoStrategy for list/IN parameters: "native" (default) or "dynamic". See List parameter strategies.

Language keys

Valid keys in the gen map:

KeyLanguage
javaJava (JDBC)
kotlinKotlin (JDBC)
rustRust (sqlx)
pythonPython (psycopg3 / sqlite3 / mysql-connector)
typescriptTypeScript
javascriptJavaScript (JSDoc types)
goGo (database/sql)

List parameter strategies

When a query uses -- @ids type[] to pass a list to WHERE id IN (@ids), sqltgen rewrites the SQL in one of two ways.

native (default)

A single bind is used with an engine-native JSON/array expression. The list size does not need to be known at code-generation time.

EngineRewritten SQL
PostgreSQLWHERE id = ANY($1) — native PostgreSQL array
SQLiteWHERE id IN (SELECT value FROM json_each(?)) — JSON array string
MySQLWHERE id IN (SELECT value FROM JSON_TABLE(?, '$[*]' COLUMNS (value BIGINT PATH '$')))

dynamic

The IN (?,?,…) clause is built at runtime with one placeholder per element. The SQL string is reconstructed on every call.

"java": { "out": "gen", "package": "com.example.db", "list_params": "dynamic" }

Use dynamic when:

  • Your driver does not support the native array/JSON approach.
  • You prefer simple, portable SQL.
  • Lists are always small and performance is not a concern.

Complete example

{
  "version": "1",
  "engine": "postgresql",
  "schema": "migrations/",
  "queries": {
    "users":  "sql/users.sql",
    "posts":  ["sql/posts.sql", "sql/post_tags.sql"],
    "search": "sql/search/**/*.sql"
  },
  "gen": {
    "java": {
      "out": "src/main/java",
      "package": "com.example.db",
      "list_params": "dynamic"
    },
    "typescript": {
      "out": "src/db",
      "package": ""
    }
  }
}