Tools in the query

These tools live inside a RETURN (or in a comment on the same query). You do not prefix the statement — you write them as expressions.

Statement-level tools (EXPLAIN, FORMAT, SHOW …) are on Statement tools .

Type inspection

TYPEOF() returns the FeatureQL type. SQLTYPEOF() returns the type in the target backend. These can differ — FeatureQL BIGINT is BIGINT on DuckDB, integer on Trino, and Int64 on serving:

FeatureQL
RETURN
    n := 1,
    fql_type := TYPEOF(n),
    backend_type := SQLTYPEOF(n)
;
Result
N BIGINTFQL_TYPE VARCHARBACKEND_TYPE VARCHAR
1BIGINTBIGINT

If a query works on one backend and not another, compare the two. Same playground: Types .

Versions

VERSION() returns the FeatureMesh registry version (and, on a local development registry, the last reload time). SQLVERSION() returns the active dialect name and the backend engine version string — the same FeatureQL-vs-backend split as TYPEOF() / SQLTYPEOF():

FeatureQL
RETURN
    dialect_known := SQLVERSION()[dialect] IN (
        'DUCKDB',
        'TRINO',
        'BIGQUERY',
        'DATAFUSION'
    ),
    has_engine_version := LENGTH(SQLVERSION()[version]) > 0
;
Result
DIALECT_KNOWN BOOLEANHAS_ENGINE_VERSION BOOLEAN
truetrue

Use bracket access for single fields: VERSION()[version], VERSION()[reloaded_at], SQLVERSION()[dialect], SQLVERSION()[version].

DESCRIBE() — metadata as columns

DESCRIBE(expr) returns a typed metadata row (name, type, entity, unit, description, status, attributes, presentation, inputs, dependencies, formula, literal_status, grain, additivity, determined_by). Nested bags (attributes, presentation, inputs, dependencies) are JSON serialized as VARCHAR when non-empty. grain is JSON direct_grain; additivity and determined_by come from the semantic profile. It works on any expression — not only persisted features — and is the SELECT-friendly counterpart to TYPEOF() when you need catalog fields as well as the type:

FeatureQL
DEFINE
    amount := 1.5::DOUBLE@CURRENCY.USD
RETURN
    DESCRIBE(amount)[name],
    DESCRIBE(amount)[type],
    DESCRIBE(amount)[entity],
    DESCRIBE(amount)[unit],
    DESCRIBE(amount)[formula]
;
Result
NAME VARCHARTYPE VARCHARENTITY VARCHARUNIT VARCHARFORMULA VARCHAR
AMOUNTDOUBLE@CURRENCY.USDNULLCURRENCY.USD1.50::DOUBLE@CURRENCY.USD

inputs and dependencies expose the local graph for the expression:

FeatureQL
DEFINE
    x := INPUT(BIGINT),
    y := x + 1
RETURN
    DESCRIBE(y)[name],
    DESCRIBE(y)[inputs],
    DESCRIBE(y)[dependencies],
    DESCRIBE(y)[literal_status]
FOR
    x := BIND_VALUE(1)
;
Result
NAME VARCHARINPUTS VARCHARDEPENDENCIES VARCHARLITERAL_STATUS VARCHAR
Y["X"]{"X":1,"Y":2}NOT_LITERAL

literal_status is LITERAL for constants, LITERAL_COMPUTED for foldable expressions, and NOT_LITERAL once an INPUT (or other runtime value) is in the chain:

FeatureQL
DEFINE
    z := 42,
    w := 1 + 2,
    x := INPUT(BIGINT),
    y := x + 1
RETURN
    DESCRIBE(z)[literal_status],
    DESCRIBE(w)[literal_status],
    DESCRIBE(y)[literal_status]
FOR
    x := BIND_VALUE(1)
;
Result
LITERAL VARCHARCOMPUTED VARCHARRUNTIME VARCHAR
LITERALLITERAL_COMPUTEDNOT_LITERAL

Prefer RETURN DESCRIBE(…) when you want columns you can project with [field] access. The DESCRIBE statement (JSON cell, optional FIELDS) is on Statement tools . Function reference: DESCRIBE() .

RETURN TRACE

RETURN TRACE evaluates a feature and every upstream dependency, returning inputs first and the requested feature last. Use it when intermediate values help debug a computation.

Playgrounds (local and persisted chains) live on Explore features .

Warnings

FeatureQL returns warnings alongside successful translation or execution (for example UNUSED-FEATURE when a DEFINE feature is not reachable from the RETURN list). They do not block the query; they surface in query(), translate(), validate(), and the warnings field on API responses.

Each warning includes a stable acknowledgement token derived from its code and message, appended as (acknowledge with ACK-XXXX). To silence a warning you accept, put that token in any line or block comment in the same query (-- ACK-XXXX or /* … ACK-XXXX … */); placement does not matter. A comment that contains an ACK-XXXX token with no matching warning produces STALE-WARNING-ACK — remove the leftover token from the query. Persisted views use the same tokens in the view body; create, replace, and refresh fail until the warning is acknowledged.

Related