Language design overview

This section describes how FeatureQL is designed: what each design choice constrains, what it allows in return, and where it stops. Each page covers one topic and shows it running. The examples are blocks in the page's .slt file and run in the conformance suite .

The mental model: a graph of formulas

FeatureQL uses SQL's keywords and expression syntax. Its model is different. A query is a flat list of named definitions. Each definition is a feature: a function from its inputs to a value, with no data in it. Tables enter at two places only: EXTERNAL_COLUMNS, where a feature reads a source, and FOR, where a query binds keys.

Three consequences differ from SQL.

Definition order does not matter. The engine sorts the dependency graph and evaluates in dependency order, as a spreadsheet does with its cells.

Evaluation is lazy. A feature that is not reachable from RETURN is never evaluated.

FeatureQL
DEFINE
    c := a / 0,
    b := a * 2,
    a := INPUT(BIGINT)
RETURN
    b
FOR
    a := BIND_VALUE(21)
;
Result
B BIGINT
42

A is used before it is defined. C divides by zero and the query still returns, because C is not reachable from RETURN.

FOR is the universe, not a filter. It names every key the graph may read. The query WHERE restricts which rows are presented. Binding one key and expecting a traversal to reach other keys returns a result limited to the bound key.

The pages

PageTopic
Composition and substitution Reuse by name, publishing, VARIANT, macros
Semantic contracts Datatype, entity, unit, multiplicity, additivity
Purity and determinism Where non-determinism can enter, ties, repeatable randomness
Absence, emptiness and errors NULL, empty sets, COUNT, runtime errors, TRY
Decoupled from execution Backends, generated SQL, serving
Strictness and canonical form Errors, warnings, permissive and strict syntax
The registry Validation of changes, history
Scopes and termination The two scopes, bounded iteration
FeatureQL and language models Why this design suits generated code

Constraints and what they allow

ConstraintWhat it allows
A feature is a single named calculationReuse at any grain, as an API or as a variant, without restating logic
PERSIST publishes, DEFINE hidesEncapsulation without keywords, and audit of what is hidden
First order, acyclic, iteration with a static boundEvery query terminates
Two scopesEvery dependency of a feature is visible at graph level
Five contracts declared where data entersA feature can be composed without reading its definition. Wrong joins, units and rollups fail to compile
No implicit coercion between computed valuesThe same result on backends that widen differently
PurityVARIANT is safe, results rerun identically, a graph is validated without executing it
A compiler, not an engineYour warehouse and your tuning. The generated SQL is yours to keep
Serving by key onlyServing cost is bounded by the keys fetched
The registry validates every changeAuthoring in a namespace without a review queue
Structure is constrained, vocabulary is notA large standard library, UDFs, macros and hybrid SQL, with composition preserved around them

Limits

These hold across the whole section. The other pages refer to this list.

  • Guarantees follow from declarations. The compiler does not read data. A false declaration at a source gives a wrong result with no error. In particular, grain is declared: two source rows with the same BIND TO key fan out. See Semantic contracts and Data contracts .
  • Intent is not checked. A feature can be well typed and deterministic and still encode the wrong business rule.
  • Cross-backend equality is tested, not proved. The conformance suite covers DuckDB, Trino, and serving (DataFusion). A capability a backend lacks is a compile-time error that names it.
  • The physical plan belongs to the backend. Nothing in this section is a claim about performance.
  • There is no formal semantics. The properties shown here are checked by the conformance suite. There are no reduction rules and no proofs.