Query tools

FeatureQL includes built-in tools for inspecting, debugging, and exploring your features — all accessible from within the query language itself.

Inspecting queries with EXPLAIN

Prefix any query with EXPLAIN to see the generated SQL, output schema, and entity relationships without executing it:

FeatureQL
EXPLAIN SELECT 1 AS FEATURE1, FEATURE1 + 1 AS FEATURE2;
Result
OUTPUT VARCHAR
{query_sql: WITH\nCTE_GCY637ZF_0 AS (\nSELECT\n\t1 AS FEATURE1\n), \nCTE_GCY637ZF_1 AS (\nSELECT\n\t(FEATURE1 + 1) AS FEATURE2, \n\tFEATURE1\nFROM CTE_GCY637ZF_0\n)\nSELECT FEATURE1, FEATURE2\nFROM CTE_GCY637ZF_1\n, query_outputs: [[FEATURE1, BIGINT], [FEATURE2, BIGINT]], entities: NULL, user: {user: {id: WEBGUEST_USER_NIC, role: GUEST}, project_id: WEBGUEST_PROJECT_SLTTESTS}}

This is the fastest way to check what SQL FeatureQL will produce for a given query. The query_sql field shows the CTE structure, query_outputs lists the result columns with their types, and entities shows any entity relationships discovered.

Inspecting features with DESCRIBE

DESCRIBE shows metadata about a specific feature — its function, parameters, dependencies, and type information:

FeatureQL
CREATE TEMPORARY FEATURES AS SELECT 1 AS FEATURE1, FEATURE1 + 1 AS FEATURE2;
DESCRIBE FEATURE2;
Result
OUTPUT VARCHAR
[{name: FEATURE2, function: ADD, params: {expr1: {kind: IDENTIFIER}, expr2: {kind: LITERAL}}, status: DEV, position: 0.0, meta: {}, properties: {mode_overwrite: NORMAL, mode_temporary: TEMPORARY}, unnamed_dependencies: {}, id: 2E6S99CCGW1E, feature_type: {}, input: [], signature: NULL, dependencies: {}, restrictions: [], inputs: [], formula: NULL, computed_properties: {}}]

Use this when you need to understand how a feature is defined, what it depends on, or what type it produces. It works with both temporary and persisted features.

Formatting queries with FORMAT

FORMAT rewrites a query into its canonical form without executing it. This is useful for normalizing syntax and auto fixing non strict constructs.

Use FORMAT (ESCAPED) to get output with markers instead of actual newlines, which is useful for programmatic comparisons.

Strict mode and FIX

By default, FeatureQL operates in strict mode. Constructs like STRUCT, LIST, and type aliases like INT64 are rejected. Add /* NON-STRICT */ to bypass strict checks, and combine with FORMAT (FIX) to rewrite them into canonical forms:

FeatureQL
/* NON-STRICT */
FORMAT (FIX) SELECT F1 := STRUCT[1, 2 AS name], F2 := LIST(3, 4);
Result
OUTPUT VARCHAR
SELECT F1 := ROW(1, 2 AS NAME), F2 := ARRAY[3, 4];

FIX rewrites STRUCT to ROW(...), LIST to ARRAY[...], normalizes bracket/parenthesis mismatches on ROW and ARRAY, and moves BIND_VALUES from the WITH clause to a FOR clause.

Alias normalization

FORMAT always normalizes function aliases (LENLENGTH, MODMODULO, POWERPOW, NOWCURRENT_TIMESTAMP) and type aliases (INT64BIGINT, FLOAT64DOUBLE, STRINGVARCHAR, BOOLBOOLEAN, INTEGERINT) to their canonical names.

FeatureQL
/* NON-STRICT */
FORMAT SELECT F1 := LEN('hello'), F2 := MOD(10, 3);
Result
OUTPUT VARCHAR
SELECT F1 := LENGTH('hello'), F2 := MODULO(10, 3);

Recreating features with SHOW CREATE

SHOW CREATE FEATURES returns the FeatureQL code needed to recreate one or more features. This is useful for understanding how features are stored internally and for exporting definitions.

For temporary features:

FeatureQL
START TRANSACTION;
CREATE TEMPORARY FEATURES AS SELECT 1 AS FEATURE1, FEATURE1 + 1 AS FEATURE2;
SHOW CREATE FEATURES FEATURE1, FEATURE2;
COMMIT;
Result
OUTPUT VARCHAR
CREATE FEATURES AS SELECT FEATURE1 := 1, FEATURE2 := FEATURE1 + 1;

Notice that FeatureQL reorders features by dependency layer and may rewrite syntax — 1 becomes VALUE(1), for example. The semantics are preserved even when the surface syntax changes.

For persisted features, the output includes full namespace paths:

FeatureQL
CREATE OR REPLACE FEATURES AS
SELECT
    1 AS FM.TUTORIALS.QUERYTOOLS.FEATURE1,
    FM.TUTORIALS.QUERYTOOLS.FEATURE1 + 1 AS FM.TUTORIALS.QUERYTOOLS.FEATURE2
;
Result
feature_name VARCHARstatus VARCHARmessage VARCHAR
FM.TUTORIALS.QUERYTOOLS.FEATURE2CREATEDFeature created as not exists
FM.TUTORIALS.QUERYTOOLS.FEATURE1CREATEDFeature created as not exists

FeatureQL
SHOW CREATE FEATURES FM.TUTORIALS.QUERYTOOLS.FEATURE2;
Result
OUTPUT VARCHAR
CREATE FEATURES AS SELECT FM.TUTORIALS.QUERYTOOLS.FEATURE1 := 1, FM.TUTORIALS.QUERYTOOLS.FEATURE2 := FM.TUTORIALS.QUERYTOOLS.FEATURE1 + 1;

Features are topologically ordered by their dependency graph, making the output self-contained — you can run it directly to recreate the features.

Cross-dialect SQL output

Specify a target dialect to see the actual SQL that would run in a specific backend:

FeatureQL
SHOW CREATE FEATURES (LANGUAGE DUCKDB)
    FM.TUTORIALS.QUERYTOOLS.FEATURE1,
    FM.TUTORIALS.QUERYTOOLS.FEATURE2
;
Result
OUTPUT VARCHAR
WITH/* stage.layer=0 stage.fields_or_features_to_compute=['FM.TUTORIALS.QUERYTOOLS.FEATURE1'] stage.layer_functions=['VALUE'] stage.fields_or_features_to_report=[] features_non_affected=[] where_for_this_layer=EmptyExpr(kind=<ExpressionTypeEnum.EMPTY: 'EMPTY'>, type=EmptyType(), value=None) => stage.cte_type=<CteTypeEnum.STANDARD: 'STANDARD'> */CTE_2Y7H9CHY_0 AS (SELECT/* */ 1 AS "FM.TUTORIALS.QUERYTOOLS.FEATURE1"), /* stage.layer=1 stage.fields_or_features_to_compute=['FM.TUTORIALS.QUERYTOOLS.FEATURE2'] stage.layer_functions=['ADD'] stage.fields_or_features_to_report=['FM.TUTORIALS.QUERYTOOLS.FEATURE1'] features_non_affected=[] where_for_this_layer=EmptyExpr(kind=<ExpressionTypeEnum.EMPTY: 'EMPTY'>, type=EmptyType(), value=None) => stage.cte_type=<CteTypeEnum.STANDARD: 'STANDARD'> */CTE_2Y7H9CHY_1 AS (SELECT/* */ ("FM.TUTORIALS.QUERYTOOLS.FEATURE1" + 1) AS "FM.TUTORIALS.QUERYTOOLS.FEATURE2", "FM.TUTORIALS.QUERYTOOLS.FEATURE1"FROM CTE_2Y7H9CHY_0)SELECT /* */ "FM.TUTORIALS.QUERYTOOLS.FEATURE1", "FM.TUTORIALS.QUERYTOOLS.FEATURE2"FROM CTE_2Y7H9CHY_1

Supported dialects: DUCKDB, TRINO, BIGQUERY, DATAFUSION. The output includes CTEs, stage comments, and dialect-specific syntax — useful for understanding how FeatureQL maps to your backend.

Exploring documentation

SHOW DOCS lets you search the built-in documentation without leaving the query environment:

FeatureQL
SHOW DOCS (
    EXCLUDE (content),
    INCLUDE (LENGTH(name) as lname)
)
WHERE lname>30 and category = 'DOC_PAGE'
ORDER BY name ASC
LIMIT 5
Result
NAME VARCHARCATEGORY VARCHARDISPLAY_ORDER ARRAYLNAME BIGINT
1-concepts/1-why_featuremesh.mdDOC_PAGE[1, 1]31
1-concepts/2-design_philosophy.mdDOC_PAGE[1, 2]33
1-concepts/3-batch_analytics.mdDOC_PAGE[1, 3]31
1-concepts/4-real_time_serving.mdDOC_PAGE[1, 4]33
1-concepts/5-business_use_cases.mdDOC_PAGE[1, 5]34

Filter by category, search content with LIKE, and sort results to find relevant pages, code samples, and function references. Combined with SHOW FUNCTIONS and SHOW FUNCTION SIGNATURES (covered in Operators & Functions ), these tools make FeatureQL largely self-documenting.

Code samples

They represent end to end tests for capabilities. They use the SLT formalism to describe the test.

# name_of_the_test
query FEATURE1:I,FEATURE2:I,?:I [rowsort]
SELECT
    FEATURE1 := 1,
    FEATURE2 := 2,
    FEATURE1 + FEATURE2
;
----
1   2   3
null

The line query represent the expected output of the query: column names and types.

Types in SLT queries are represented as:

TypeCode
IntegerI
DecimalD
StringV
BooleanB
TemporalT
JSONJ
RowR
Array of scalarsA
Array of rowsQ
Last update at: 2026/03/14 14:27:33
Last updated: 2026-03-14 14:28:11