Skip to main content

An alternative to Terraform for SQL databases without using a state.

Project description

SQLIaC — SQL Infrastructure as Code

An alternative to Terraform for SQL databases — without a state file.

SQLIaC lets you declare SQL database resources (databases, schemas, tables, roles, views, warehouses, grants…) in TOML definition files. Under the hood it queries the live database to detect drift, then renders and executes Jinja-templated DDL to bring the database into the declared state. No state file. No lock file. Just your definitions and the database.

How It Works

  1. You declare resources in ./definitions/*.toml — one file per resource type.
  2. SQLIaC queries the live database using state.sql templates to discover what currently exists.
  3. Drift is detected by comparing definition → state; actions are determined: CREATE, ALTER, DROP, or no-op.
  4. Jinja-templated DDL renders the appropriate SQL statements.
  5. Execution runs in parallel respecting a dependency DAG built from your definitions.

Installation

pip install sqliac

You'll also need at least one database adapter:

pip install sqliac-snowflake   # Snowflake
# pip install sqliac-postgres  # PostgreSQL (future)
# pip install sqliac-oracle    # Oracle (future)
# pip install sqliac-databricks# Databricks (future)

Quick Start

1. Scaffold a project

sqliac init

This creates:

.sqliac/
├── provider/
│   ├── config.toml          # resource registry with DDL commands & context schemas
│   ├── credentials.toml     # database connection credentials
│   ├── database/
│   │   ├── ddl_template.sql # Jinja DDL template
│   │   └── state.sql        # state introspection query
│   ├── schema/
│   │   ├── ddl_template.sql
│   │   └── state.sql
│   └── table/
│       ├── ddl_template.sql
│       └── state.sql
definitions/
├── database.toml             # declare your databases here
├── schema.toml               # declare your schemas here
└── table.toml                # declare your tables here
.agents/skills/sqliac/        # AI agent skill for generating template pairs

The scaffolding includes working examples (Snowflake DDL + state queries for database, schema, and table). Adjust the provider config to match your engine and resources.

2. Configure credentials

export SNOWFLAKE_ACCOUNT="my_account"
export SNOWFLAKE_USER="my_user"
export SNOWFLAKE_PASSWORD="my_password"
export SNOWFLAKE_WAREHOUSE="my_warehouse"

Or write them in .sqliac/provider/credentials.toml (env vars take precedence):

[snowflake]
account = "my_account"
user = "my_user"
password = "my_password"
warehouse = "my_warehouse"

3. Declare your resources

Edit the definition files under definitions/. For example, definitions/schema.toml:

[[schema]]
object_name = "MY_DB.STAGING"
transient = false
managed_access = false
data_retention_time_in_days = 1
comment = "Staging schema"
[schema.depends_on]
database = ["MY_DB"]

[[schema]]
object_name = "MY_DB.PRODUCTION"
transient = false
[Sschema.depends_on]
database = ["MY_DB"]
  • object_name — fully qualified name (uppercase by convention)
  • depends_on — declare ordering constraints between resources
  • wait_time — optional delay (seconds) between DDL execution and the next resource

4. Preview and apply

sqliac apply --dry-run     # see what would change
sqliac apply               # execute for real

5. Tear down

sqliac destroy --dry-run   # preview cleanup
sqliac destroy             # drop all declared resources (in reverse DAG order)

CLI Reference

Command Description
sqliac init Create project scaffolding with example templates and the agent skill
sqliac list Show installed adapters and their available resource types
sqliac graph Generate a dependencies.dot DAG file from your definitions
sqliac compile --ddl create|alter|drop <resource> Render a DDL template with example context from config.toml
sqliac compile --state <resource> Render a state query with example context from config.toml
sqliac apply Compare definitions against live state and reconcile
sqliac destroy Drop all declared resources in reverse dependency order

Apply / Destroy options

sqliac apply [--threads N] [--dry-run]
sqliac destroy [--threads N] [--dry-run]
  • --threads — number of parallel workers (default: 3). Tasks execute concurrently within each topo-sorted batch of the DAG.
  • --dry-run — preview what SQL would be executed without touching the database.

Logging

sqliac --log debug apply       # console logging
sqliac --log-out debug apply   # file logging (sqliac.log)

Provider Templates

Each resource type registered in .sqliac/provider/config.toml must have:

.sqliac/provider/<resource>/
├── ddl_template.sql    # Jinja DDL for CREATE/ALTER/DROP
└── state.sql           # query returning current state as a single JSON row

Core invariant

The keys returned by state.sql must be a 1:1 match with the Jinja variables consumed by ddl_template.sql.

If ddl_template.sql references add.get('warehouse'), then state.sql must return JSON containing warehouse. The tool detects mismatches and reports them at runtime, but you can validate pairs ahead of time using the agent skill's check script.

The compile command

Use sqliac compile to iterate on templates without applying:

sqliac compile --ddl create database    # renders the CREATE/ALTER DDL
sqliac compile --state database         # renders the state introspection query

The compile command reads the example ddl_context from config.toml, so keep it populated with realistic values — it serves as documentation, test fixture, and developer playground all at once.

Dependency Graph

Resources can declare inter-resource dependencies via depends_on. SQLIaC builds a DAG and executes in topo-sorted waves:

[[schema]]
object_name = "MY_DB.STAGING"
[schema.depends_on]
database = ["MY_DB"]
  • apply — resources with no dependencies run first; downstream resources wait for their deps to succeed.
  • destroy — the DAG is reversed so dependents are dropped before their dependencies.
  • Circular dependencies are detected and reported with visual inline diagnostics.
sqliac graph   # writes dependencies.dot + prints to terminal

The sqliac Agent Skill

SQLIaC ships with an agent skill (for AI coding assistants like OpenCode, Cursor, etc.) that automates writing ddl_template.sql and state.sql pairs. To use it:

  1. Run sqliac init — the skill is copied into .agents/skills/sqliac/.
  2. Ask your AI assistant: "create Snowflake templates for warehouse" and reference the .agents skill directory.

The skill:

  • Reads engine-specific reference files (Snowflake, PostgreSQL, Oracle, Databricks patterns).
  • Produces a validated ddl_template.sql + state.sql pair with correct Jinja + SQL.
  • Registers the resource in config.toml with example values.
  • Runs check_key_parity.py to verify key parity between the template and state query.

See .agents/skills/sqliac/SKILL.md for the full skill documentation.

Drift Detection

On each apply, SQLIaC:

  1. Executes state.sql to fetch the live state as JSON.
  2. Recursively normalizes both the definition and the state (filtering, sanitizing, aligning nested keys).
  3. Runs a structured diff via dictdiffer to produce add, change, and remove sections.
  4. Feeds those sections into the Jinja DDL template, which renders the appropriate CREATE OR ALTER, ALTER, or DROP statements.

If the resource does not exist (state query returns zero rows), a CREATE is generated. If no differences are found, no DDL is executed.

Adapters

Adapters are self-contained packages discovered via Python entry points (sqliac.adapters group). Each adapter provides:

  • A credentials dataclass with validation
  • A connection manager for thread-safe connection pooling
  • An adapter class wrapping query execution

All adapters follow the base classes in sqliac.adapters.base, making it straightforward to add support for new database engines.

Project Layout

.sqliac/                  # config directory
├── provider/
│   ├── config.toml       # resource registry
│   ├── credentials.toml  # connection credentials
│   └── <resource>/       # one dir per resource type
│       ├── ddl_template.sql
│       └── state.sql
definitions/              # your resource declarations
├── database.toml
├── schema.toml
└── table.toml
.agents/skills/sqliac/    # AI agent skill for template generation

License

MIT © Ruslan Gonzalez Konstantinov

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sqliac-0.1.8.tar.gz (49.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sqliac-0.1.8-py3-none-any.whl (51.3 kB view details)

Uploaded Python 3

File details

Details for the file sqliac-0.1.8.tar.gz.

File metadata

  • Download URL: sqliac-0.1.8.tar.gz
  • Upload date:
  • Size: 49.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Pop!_OS","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for sqliac-0.1.8.tar.gz
Algorithm Hash digest
SHA256 946c6c0ec30fe19652cb91d1db94f37b93c0aaa2172335b719ef6f014c27069a
MD5 59f90eab74f68afd0b6d5fba40ccab3e
BLAKE2b-256 ea521c1f788ef74807befe1e14005d9f2415ed3f2861e8de5b0ac896879ccd84

See more details on using hashes here.

File details

Details for the file sqliac-0.1.8-py3-none-any.whl.

File metadata

  • Download URL: sqliac-0.1.8-py3-none-any.whl
  • Upload date:
  • Size: 51.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Pop!_OS","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for sqliac-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 c3a41a9313b52d55230dabc2ed16296273a3027c6ed871a145800543965e94a2
MD5 7487ff96675a708b775b74cbf6f100bc
BLAKE2b-256 b6c421a972d4165b5d9caf688e7925bc434aa3d00d3d29aa1011e389a6001c49

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page