Overview

From sqlc: one command#

scythe migrate sqlc.yaml

This reads your sqlc config (v1 or v2 format), converts query annotations, and generates a scythe.toml. If your database engine lacks scythe backend support for your language, the migration tool stops and reports both sides rather than generating an incomplete config.

What changes in the config format

sqlc.yaml (before):

version: "2"
sql:
  - schema: "sql/schema.sql"
    queries: "sql/queries.sql"
    engine: "postgresql"
    gen:
      go:
        out: "db"
        package: "db"

scythe.toml (after):

[scythe]
version = "1"
 
[[sql]]
name = "main"
engine = "postgresql"
schema = ["sql/schema.sql"]
queries = ["sql/queries.sql"]
output = "db"
 
[sql.gen.go]
target = "pgx"

The migration tool picks the driver from your sqlc engine setting: pgx for PostgreSQL, database-sql for MySQL/SQLite/DuckDB/SQL Server, godror for Oracle, gosnowflake for Snowflake — adjust per Configuration if needed.

What changes in query annotations

sqlc (before):

-- name: GetUser :one
SELECT * FROM users WHERE id = $1;
 
-- name: CreateUser :exec
INSERT INTO users (name, email)
VALUES (sqlc.arg(name), sqlc.arg(email));

scythe (after):

-- @name GetUser
-- @returns :one
SELECT * FROM users WHERE id = $1;
 
-- @name CreateUser
-- @returns :exec
INSERT INTO users (name, email)
VALUES ($1, $2);
What has no direct equivalent
  • sqlc.embed() — replace with explicit column selection.
  • sqlc.slice() — replace with = ANY($1) array parameter.
  • sqlc.narg() converts to a positional parameter with a @param annotation documenting the original name, but nullability is not inferred from it — add @nullable manually if the column itself isn't already nullable.
Feature comparison
Feature sqlc scythe
Annotation style -- name: Foo :one -- @name Foo + -- @returns :one
Named parameters sqlc.arg(name) $1, $2, …
Config format YAML TOML
Nullable overrides Go struct tags -- @nullable col1, col2
Non-null overrides Not supported -- @nonnull col1
JSON column types Not supported -- @json data = MyType
Deprecation markers Not supported -- @deprecated Use V2

After migration#

  1. Review the generated scythe.toml.
  2. Verify with scythe check.
  3. Generate code with scythe generate.
  4. Run scythe lint to catch issues sqlc might have missed.

Custom type mappings and ORM-specific extensions need manual review after migration — they aren't preserved automatically.

From sqlfluff: command replacement#

Scythe integrates sqruff (a Rust reimplementation of sqlfluff) and adds 23 codegen-aware rules plus 35 security and migration-safety rules on top.

sqlfluff scythe
sqlfluff lint file.sql scythe lint file.sql
sqlfluff fix file.sql scythe lint --fix file.sql
sqlfluff format file.sql scythe fmt file.sql

Configuration moves from .sqlfluff (INI) to scythe.toml:

# .sqlfluff (before)
[sqlfluff]
dialect = postgresql
exclude_rules = LT01,LT02
# scythe.toml (after)
[[sql]]
engine = "postgresql"
 
[lint.sqruff.rules]
"LT01" = "off"
"LT02" = "off"

Scythe requires setting each sqruff rule individually under [lint.sqruff.rules], using bare codes without the SQ- prefix. Not all sqlfluff rules are implemented in sqruff — check the sqruff repository for current coverage.

Next Steps#

  • CLI Reference for the full flag list on scythe migrate, scythe lint, and scythe fmt.
  • Linting for what scythe's own 23 schema-aware rules catch that sqlfluff/sqruff can't.

Updated

Was this page helpful?