HomePlaygroundExpressionsDocsDriversBlogStatusRoadmapChangelog GitHub

๐Ÿช QAIL

The AST Protocol

One query language. Every layer.

QAIL eliminates hand-written endpoints, query builders, and ORM abstractions with a single AST that flows from schema to database โ€” binary-encoded, type-safe, with built-in Row-Level Security.

QAIL AST
Qail::get("users")
    .select_all()
    .filter("active", Eq, true)
POSTGRESQL
SELECT * FROM users WHERE active = true
QDRANT
{ "must": [{ "key": "active", "match": true }] }
cargo install qail
zig fetch --save ...qail-zig/v0.2.0.tar.gz
Rust Python Go PHP Java Node C/C++ Rust Python Go PHP Java Node C/C++

Native Rust โ€ข Universal C-API โ€ข FFI Bindings

Real Benchmark: N+1 Battle Test

Same query. Same database. Same 50-row result set with 3 JOINs.
100 iterations, release build, buffer cache warmed.
Snapshot run: February 2026.

QAIL AST
449ยตs
1 query
GQL + DataLoader
1.52ms
~3 queries
GQL Naive
18.2ms ยท 40ร— slower
~151 queries
REST Naive
22.5ms ยท 50ร— slower
~151 queries

QAIL executes one planned query on this path. Naive resolver/endpoint patterns can explode to 151 round-trips without join batching.

View all benchmarks โ†’

The QAIL Stack

Four layers. One AST flows through all of them.

๐Ÿงฌ

qail-core

THE AST

Parser, transpiler, type system. Queries are data structures, not strings. Schema validation at compile time.

get users fields id, email
  where active = true
  order by created_at desc
  limit 10
๐Ÿ”Œ

qail-pg / qdrant

NATIVE DRIVERS

Direct wire protocol. Built-in RLS context per connection. No SQLx middleman. Facts + Meaning.

let driver = PgDriver::connect_env().await?;
driver.set_rls_context(
    RlsContext::operator("op-456")
).await?;
driver.fetch_all(&cmd).await?
๐Ÿš€

qail-gateway

AUTO-REST + BINARY PROTOCOL

Zero-code API from your schema. Auto-REST with FK expansion, policy engine, WebSocket subscriptions, binary AST wire format.

GET /api/bookings
    ?status.eq=confirmed
    &sort=created_at:desc
    &expand=routes,payments
    &limit=20
โš™๏ธ

qail-workflow

STATE MACHINES

Declarative multi-step orchestration. Database queries, notifications, and events in typed state machines.

Workflow::new("booking")
    .step("validate", validate_fn)
    .step("charge", payment_fn)
    .step("confirm", confirm_fn)
    .on_error(rollback_fn)

Every Entry Point โ†’ One Pipeline

REST params, text queries, or binary AST โ€” all converge to the same struct. Policy injection and schema validation happen once, on the AST.

REST
GET /api/users?active=true
Text
get users where active = true
Binary
bincode::serialize(&cmd)
โ†“
QAIL AST
Qail { action: Get, table: "users", cages: [Filter(active = true)] }
โ†“
POLICY ENGINE
+ injects AND operator_id = 'op-456'
โ†“
TRANSPILER
cmd.to_sql() โ†’ SELECT * FROM users WHERE active = true AND operator_id = 'op-456'
โ†“
POSTGRESQL (with PG-native RLS)
1 query. 1 connection. Done.

Supported Databases

One AST. Two powerhouses. Cache built-in.

PostgreSQL

PostgreSQL

Relational โ€ข Transactions โ€ข ACID

Production
Qdrant

Qdrant

Vector โ€ข AI/ML โ€ข Semantic Search

Production

Native Cache

Moka โ€ข TTL โ€ข Zero Latency

Built-in

Language Drivers

Native packages for your language. All powered by one Rust core.

Zig

Zig

Pure Zig โ€ข TLS โ€ข Pool v0.2.0
Rust

Rust

cargo add qail-core Cargo
PHP

PHP

31K q/s โ€ข 2.6x Eloquent GitHub
Go

Go

126K q/s โ€ข 4.2x GORM GitHub
Python

Python

130K rows/s COPY GitHub
Node.js

Node.js

FFI โ€ข Native Addon GitHub

View all drivers โ†’

๐Ÿ›ก๏ธ The "Wait, Stop!" Feature

The only migration tool that reads your code before it touches your data.

Terminal
$ qail migrate up schema.qail --codebase ./src

๐Ÿ›‘ BLOCKED: Safety Check Failed

You are dropping column 'status', but it is still used in:

   ๐Ÿ“„ src/queries.ts:25  โ†’ get portfolio fields status
   ๐Ÿ“„ src/api.rs:102     โ†’ Qail::get("portfolio").filter("status"...)

Fix your code first, or use --force to proceed.
๐Ÿ”

Scans Before Running

Searches .rs, .ts, .js, .py for queries that reference changing columns

๐Ÿ“

Points to Line Numbers

Shows exactly where your code needs updating before migration

๐ŸŽฏ

You're the Boss

Use --force to override when you know better

The data layer you don't write.

One AST. Binary wire. Compile-time safety. Built-in RLS.