Exactly how SQL should be written
SQL generation for
schemas + queries
Write schemas in ASL, queries in AQL. Axel compiles both to clean PostgreSQL SQL — migrations and parameterized query strings. No ORM, no driver, no runtime magic.
Quick look
Define models in ASL, query shapes in AQL, and get optimal single-scan PostgreSQL queries.
use extension 'pgcrypto'; type User { required id: uuid { default := gen_uuid(); constraint pk; }; required email: str { constraint exclusive; }; name: str; } type Post { required title: str; required link author: User; multi link likes: User; }
Declarative Schemas, Zero Decorator Gymnastics
Define your models, single/multi links, indexes, and custom constraints cleanly in .asl files. Axel AST-diffs your schema and generates clean, deterministic PostgreSQL migration SQL automatically.
type Article extending Base { required title: str; slug: str { constraint exclusive; }; required link author: User; multi link tags: Tag; }
Nested Shapes in a Single Database Scan
Select deeply nested relational graphs in one intuitive query. Axel compiles nested shapes into a single PostgreSQL round-trip — zero N+1 queries. Choose between two loading strategies:
query(default) — correlated subqueries withjson_aggandrow_to_jsonin theSELECTprojection.join—LEFT JOIN LATERALin theFROMclause, ideal when the planner benefits from seeing all joins together.
Set globally in axel.yaml or override per-query with @rel_load_strategy.
select Article { id, title, author: { id, email }, tags: { id, name } } filter .slug = $slug; -- compiles to json_agg + row_to_json subqueries
Ahead-of-Time Compiler, Zero Runtime Overhead
Axel is a build-time compiler producing pure parameterized SQL strings and typed structs/interfaces. There is no query engine sidecar, no connection pooling layer, and zero driver wrapping.
Explore Code GenerationExtensions, Row-Level Security, Conflicts & Triggers
Axel is purpose-built for PostgreSQL. Declare database extensions (pgvector, pg_trgm), fine-grained Row-Level Security (policy), triggers, and unless conflict upsert semantics directly in your schema and queries.
policy tenant_isolation on Organization for all using (.id = global.current_org_id);
Bring your database
into the AOT age
Get started in seconds with Axel's CLI, schema modeling, and zero-runtime query compiler.
Get Started