QAIL Zig Documentation
Zig-first PostgreSQL wire-protocol driver with AST-native query building, PostgreSQL-path parity tracking against qail.rs, and optional Linux Kerberos/GSSENC integration via the platform GSSAPI stack.
QAIL Zig is the active Zig implementation of the QAIL PostgreSQL stack. It shares the same AST direction as qail.rs, but keeps the runtime, protocol path, and tooling in Zig. The core driver path is Zig-native; Linux Kerberos/GSSENC support is an optional runtime integration with system libc/GSSAPI rather than a self-contained Zig Kerberos stack. Full qail.rs ecosystem parity is still incomplete outside the PostgreSQL-focused track.
Latest Updates (April 2026)
- qail-zig is active again and no longer documented as deferred.
- PG driver hardening now includes AST sanitization, stricter startup/auth sequencing, COPY fail-closed checks, and replication hardening suites.
- The current public benchmark story is now the dedicated qail-zig versus
pg.zigshared-surface matrix. - qail-zig now has its own versioned changelog and docs track.
- Real PostgreSQL CLI validation is now explicitly tracked for
exec,seed,pull, andmigrate status|plan|up|downpaths. - Migration receipt hardening now records full receipt fields and handles generated-version collisions for immediate back-to-back migration runs.
- Current repository snapshot: 52,795 tracked text lines total, including 50,049 lines of Zig across 169 tracked
.zigfiles. - The current qail.rs reference size for parity tracking is 209,728 total lines.
Repository Snapshot
- Total LOC: 52,795 tracked text lines in qail-zig.
- Zig LOC: 50,049 lines across 169 tracked
.zigfiles. - qail.rs total LOC: 209,728 lines.
.
├── src/ # Driver, AST, parser, protocol, runtime, CLI, tests, benches
├── scripts/ # Codegen, parity, and policy guards
├── docs/ # mdBook pages and theme overrides
├── .github/workflows/ # CI workflows
├── build.zig # Build graph and targets
└── PARITY_AST_PG_DRIVER.md
What QAIL Zig Covers
| Area | Status |
|---|---|
| PostgreSQL driver | ✅ Active |
| Connection pooling | ✅ Active |
| Prepared pipelines | ✅ Active |
| COPY in/out helpers | ✅ Active |
| TLS | ✅ Active |
| Logical replication core | ✅ Active |
| CLI | ✅ Active |
| Editor LSP (via qail.rs extension) | ✅ External |
| Security hardening suites | ✅ Active |
| qail.rs parity tracking | ✅ Active |
Implementation Positioning
- qail.rs is still the production reference and widest implementation.
- qail-zig is the serious Zig track, with active parity work and dedicated benchmarks.
- Security boundary: on the AST flow, the goal remains no application SQL string interpolation surface.
Docs Map
- Start with Installation and Quick Start.
- Use PostgreSQL Driver for transport and feature coverage.
- Use Security Hardening for the recent fail-closed work.
- Use Throughput Benchmarks and qail.rs Parity Status to track the implementation line.
Installation
Requirements
- Zig
0.16+ - PostgreSQL
14+ - macOS, Linux, or another platform supported by the Zig toolchain
Clone and Build
git clone https://github.com/qail-io/qail-zig.git
cd qail-zig
zig build -Doptimize=ReleaseFast
Optional Wrapper
./scripts/zigw is a thin convenience wrapper for common repo tasks.
Examples:
./scripts/zigw doctor
./scripts/zigw test
./scripts/zigw pgzig-bench qail single --workload point
./scripts/zigw delegates to normal zig build commands.
Docs Build
The Zig docs book is configured to publish into the existing dev.qail.io tree at public/zig/docs.
cd docs
mdbook build
Quick Start
const std = @import("std");
const qail = @import("qail");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var driver = try qail.driver.driver.PgDriver.connect(allocator, "127.0.0.1", 5432, "postgres", "mydb");
defer driver.deinit();
const cmd = qail.ast.QailCmd.get("users")
.select(&.{ qail.ast.Expr.col("id"), qail.ast.Expr.col("email") })
.where(&.{.{ .condition = .{ .column = "active", .op = .eq, .value = .{ .bool = true } } }})
.limit(10);
const rows = try driver.fetchAll(&cmd);
defer {
for (rows) |*row| row.deinit();
allocator.free(rows);
}
}
High-Level Entry Points
qail.driver.driver.PgDriver.connect(...)qail.driver.pool.PgPool.init(...)qail.driver.pipeline.Pipeline.init(...)qail.validateAst(...)
Practical Direction
- Use
PgDriverfor direct command execution and AST-native reads/writes. - Use
Pipelinefor high-throughput prepared batches. - Use
PgPoolfor concurrent prepared singles and scoped workloads. - Validate untrusted AST input with
qail.validateAstbefore execution.
PostgreSQL Driver
QAIL Zig implements PostgreSQL directly over the wire protocol. The active surface includes:
- plain TCP connections
- connection timeouts
- TLS transport
- startup/auth handling for cleartext, MD5, SCRAM, and enterprise auth hooks
- prepared statement execution
- pipeline execution
- connection pooling
- COPY helpers
- LISTEN / NOTIFY
- logical replication core
- RLS helper APIs
Primary Types
qail.driver.driver.PgDriverqail.driver.connection.Connectionqail.driver.pipeline.Pipelineqail.driver.pool.PgPool
Driver Direction
The focus of qail-zig is not a SQL-string convenience wrapper. The serious path is:
- build AST or validated command input
- encode PostgreSQL protocol frames directly
- execute over a pure-Zig transport path
- fail closed on protocol and state-machine violations
Current Emphasis
Recent work concentrated on hardening the PG driver instead of broadening surface area first. That includes startup/auth state validation, protocol framing checks, COPY sequencing checks, replication stream fail-closed handling, and AST sanitization.
Pool, Pipeline, and COPY
Pool
PgPool provides fixed-size connection pooling with scoped helpers and reset-on-release behavior.
Use it when:
- you want concurrent prepared single-query workloads
- you need pooled RLS or tenant-scoped acquisition
- you want explicit
min_connections/max_connections
Pipeline
Pipeline batches Bind + Execute messages and sends one Sync per batch. This is the highest-throughput path for prepared count-only or row-collecting workloads on a single connection.
Use it when:
- you already have a prepared statement
- batch throughput matters more than per-query latency
- you want one connection and many completions per round trip
COPY
The COPY helpers are active and hardened.
Supported areas:
- COPY FROM STDIN helpers
- COPY TO STDOUT raw export helpers
- stricter protocol sequencing checks
- fail-closed handling on malformed COPY states and oversized data
COPY is now treated as a protocol feature that must reject unexpected backend frames rather than attempting to continue.
Security Hardening
The recent qail-zig work focused on PG-driver hardening parity against qail.rs.
Added or Tightened
- AST sanitization for untrusted command input
- raw SQL escape-hatch rejection on the sanitization path
- strict runtime SQL-string allowlist checks for core/driver files
- stricter startup/auth ordering checks
- authentication method-switch rejection
- SASL final /
AuthenticationOksequencing checks - Bind / Parse parameter-count guards
- COPY fail-closed state validation
- replication stream fail-closed handling on malformed
CopyData - startup, protocol, and replication hardening suites
Why This Matters
Protocol bugs are often state-machine bugs, not just parsing bugs. The hardening work in qail-zig now rejects malformed or unexpected backend sequences earlier instead of silently progressing through them.
Current Safety Model
- AST-native execution is the preferred path.
validateAstexists for untrusted or deserialized command ingress.- Public driver execution rejects raw SQL command payloads; remaining SQL strings are confined to audited internal renderers/helpers.
- protocol handlers are moving toward explicit state validation and drain-to-ready behavior after errors.
Remaining Direction
The active parity target is not “support every surface first”. It is “close driver and hardening gaps without weakening the transport guarantees.”
QAIL Zig Benchmarks
The current public benchmark page is published at /zig/benchmarks on dev.qail.io.
The current public Zig driver comparison is:
qail-zigpg.zig
Harness
The active harness is src/benchmarks/qail_pgzig_bench.zig and reports the shared prepared-statement surface:
single— prepared single-query path on one connectionpool10— prepared singles over ten connections
It covers five workloads:
point— tiny point lookup pathwide_rows— medium result sets with wide mixed rowslarge_rows— larger result-set receive/decode pathmany_params— parameter-heavy bind/encode pathaggregate— more server-heavy aggregate slice
The methodology is intentionally strict:
- qail-zig workloads are authored as native
QailCmdASTs - qail-zig compiles them once to SQL for statement preparation
- qail-zig then runs them through its prepared protocol path
pg.zigexecutes the same prepared SQL templates through its cached prepared-query pathpipelineis excluded so the published page stays on the clearest shared modes between the two drivers
Runner Examples
# Canonical benchmark runner
zig build pgzig-bench -- qail single --workload point
zig build pgzig-bench -- pgzig single --workload point
# Optional wrapper (equivalent commands)
./scripts/zigw pgzig-bench qail single --workload point
./scripts/zigw pgzig-bench pgzig single --workload point
# Full published matrix surface
zig build pgzig-bench -- qail pool10 --workload wide_rows
zig build pgzig-bench -- pgzig pool10 --workload wide_rows
zig build pgzig-bench -- qail single --workload many_params
zig build pgzig-bench -- pgzig pool10 --workload aggregate
Latest Published 3-Round Medians
| Workload | Single (pg.zig / qail-zig) | Pool10 (pg.zig / qail-zig) |
|---|---|---|
| Point | 19,535 / 44,862 q/s | 72,251 / 158,675 q/s |
| Wide rows | 4,544 / 5,474 q/s | 16,246 / 19,062 q/s |
| Large rows | 88.306 / 90.000 q/s | 279.950 / 306.865 q/s |
| Many params | 19,118 / 41,570 q/s | 71,257 / 153,386 q/s |
| Aggregate | 228.241 / 236.793 q/s | 1,438.975 / 1,474.389 q/s |
Reading the Results
- qail-zig leads all
10 / 10shared throughput cells in the published matrix. - The biggest gains are on
pointandmany_params, which points at lower execution-path and bind-handling cost. wide_rowsalso stays positive, which means the win is not restricted to tiny dispatch-heavy lookups.- The smallest gaps are
large_rowsandaggregate, where PostgreSQL itself dominates more of the total work. - The page is intentionally narrow on feature parity. Pipeline is a qail-zig capability, but it is not part of the
pg.zigcomparison page so the benchmark stays on the clearest shared surface.
Benchmark Discipline
The benchmark numbers are only meaningful when the compared paths are equivalent. The current work explicitly separated:
- shared SQL template after qail-zig AST compilation
- matched prepared execution on both sides
- interleaved rounds with median reporting
That keeps the comparison at the driver/runtime boundary instead of turning it into a fake API-surface mismatch.
Recommended Next Reads
- Read the public benchmark page at
/zig/benchmarksfor the published matrix and interpretation. - Read
README.mdin the repo root for the short current benchmark summary. - If you want pipeline numbers, treat them as qail-zig-only capability measurements rather than as a direct
pg.zigcomparison.
qail.rs Parity Status
qail-zig tracks qail.rs as the reference implementation for PostgreSQL driver behavior and hardening.
Current Snapshot
As of 2026-04-23, the narrow AST/codegen parity checks against a local qail.rs checkout are green:
./scripts/check_codegen_sync.sh ../qail.rs->codegen sync check passed./scripts/check_parity.sh ../qail.rs->AST actions: rust=75 zig=76,Encoder actions: rust=57 zig=76,parity check passed
That means the Rust-driven AST porting/codegen path is working for its current scope, and the PostgreSQL AST encoder still covers the Rust action surface completely.
Real PostgreSQL CLI validation on the Zig side is also green on this date:
- Broad CLI matrix pass:
16/16on live DB paths (exec,seed,pull,migrate status|plan|up|down). - Migration receipt-collision stress pass:
6/6immediate dual-migrate upruns across fresh databases.
Active Areas with Strong Coverage
- AST core exports
- Rust-driven AST codegen sync
- PostgreSQL wire protocol
- prepared execution and pipelines
- pooling
- TLS transport
- COPY in/out helpers
- LISTEN / NOTIFY
- logical replication core
- RLS helper APIs
- CLI PostgreSQL execution path (
exec,seed,pull,migrate status|plan|up|down) - startup/auth policy controls
- TLS SCRAM channel-binding derivation and fail-closed precedence on TLS startup
- protocol hardening suites
- typed policy parsing and diff normalization for common
pg_dumpwrappers - typed recursive CTE AST support and typed source-query constructors for views/materialized views
Current Reality
Parity is not complete across the entire qail.rs ecosystem. The largest gaps remain outside the core PG driver track:
- gateway / auto-REST / WebSocket / OpenAPI stack
- qdrant vector driver and hybrid execution path
- workflow engine
- typed schema codegen (
qail types) and build-time SQL / N+1 guard rails - CLI breadth outside the core PG path (
qail init,types, vector/hybrid flows) - editor tooling breadth remains on the qail.rs OpenVSX LSP track (not bundled in qail-zig)
- direct SDKs and broader non-driver surfaces
Important Policy Delta
The main remaining policy difference is narrower now:
qail.rsremoved raw runtime SQL APIs from the normal execution path entirely.qail-zignow rejects.rawand nested procedural/raw escape hatches on the public driver path by default.- On TLS connections,
qail-zignow treats connection-derivedtls-server-end-pointbytes as authoritative instead of allowing caller-supplied binding overrides. qail-zignow also matches libpq-stylegssencmodepreface semantics and resolves hostnames across plain, TLS, async, and GSSENC-preface connect paths instead of assuming IPv4 literals.qail-zignow ships Linux Kerberos environment preflight diagnostics (linuxKrb5Preflight) and a built-in Linux Kerberos provider (linuxKrb5TokenProvider) via runtime GSSAPI loading on Linux.qail-zignow also exposes a session-awareGssTokenProviderExcallback shape, which removes the old API limitation that prevented Rust-style stateful GSS provider implementations.- On Linux, accepted
GSSENCRequestnow proceeds into an encrypted GSS transport instead of failing closed after the preface. - The repository now also carries a dedicated Linux Kerberos/GSSENC smoke workflow that provisions a local realm + PostgreSQL service principal and proves one AST-native roundtrip over
gssencmode=require. - Typed RLS helpers and typed policy parsing are now present on the Zig side, including normalization of common wrapped
current_setting(...)forms emitted bypg_dump. - The old raw nested-query and raw policy-SQL string fields have been removed from the Zig AST shape entirely; trusted compatibility now flows through internal helper modules and raw AST variants that the public runtime gate already rejects.
- Migration receipt recording now writes the full tracked shape (
version,name,applied_at,checksum,sql_up,sql_down) and handles generated-version collisions without aborting roll-forward migrations.
The main remaining enterprise-auth gap is narrower now:
- runtime coverage depth and maintenance burden are now the main gap, especially expanding beyond the new smoke path and keeping the local TLS/GSS compatibility layers stable across Zig upgrades
PG Driver Focus
The PG driver is the serious parity target right now. That is why recent work landed in:
- sanitization
- startup/auth sequencing
- protocol hardening
- replication hardening
- benchmark comparability
For detailed driver parity notes, see the repository parity file:
PARITY_AST_PG_DRIVER.md
API Surface
The high-signal public surface for qail-zig currently centers on the PostgreSQL driver and related tooling.
Core Exports
qail.driver.driver.PgDriverqail.ast.QailCmdqail.ast.Exprqail.validateAst
Driver Module
qail.driver.connection.Connectionqail.driver.pipeline.Pipelineqail.driver.pool.PgPoolqail.driver.tls.TlsConnectionqail.driver.connect_url.ConnectOptionsqail.driver.auth_options.AuthOptionsqail.driver.rls.RlsContext
Tooling
- CLI entry via
zig build cli - editor LSP via the published qail.rs extension (OpenVSX/VS Code)
- benchmark runners under
src/*bench*.zig
Verified Real-DB CLI Surface
qail exec: inline query,--file,--json,--tx, and--dry-runqail seed --fileon the PostgreSQL execution pathqail pullschema extraction from a live PostgreSQL databaseqail migrate status|plan|up|down, including receipt recording on live DB- database URL resolution through
QAIL_DATABASE_URL
Validation date: 2026-04-23, against local real PostgreSQL server runs.
Recommended Reading Order
- Start with the driver docs.
- Then read the hardening page.
- Then use the parity page to understand what is intentionally in-scope versus still missing.
Changelog
QAIL Zig now tracks its own release notes separately from qail.rs.
Current Highlights (Post-v0.8.1, 2026-04-23)
- Real PostgreSQL CLI matrix is validated on live DB paths for
exec(inline/file/json/tx/dry-run),seed,pull, andmigrate status|plan|up|down. - Migration receipt writes now include
applied_atandsql_downon the AST-native path, matching the migration table contract used in runtime flows. - Auto migration receipts now use conflict-safe insertion and version-retry semantics, so immediate back-to-back
migrate upcalls no longer fail on_qail_migrations_version_key. - Migration-table creation via the public AST route remains raw-policy compatible (no trusted-only column default escape hatch in that path).
- AST column-definition SQL rendering now preserves nullable-by-default columns correctly;
NOT NULLis emitted only when explicitly requested. - The Linux
PgDriver.connectand pipeline failure-metadata fixes fromv0.8.1remain in place.
For the repository changelog, see: