Namespaces & aliases

Features live in namespaces — hierarchical paths like fm.user_analytics.daily_clicks that organize the registry and prevent naming conflicts. Aliases give you shorthand access to namespaces you reference often.

Persistent vs. local features

Features in FeatureQL are either persistent (stored in the registry with an fm. prefix) or local (existing only for the duration of a query). Local features are the default — define a feature without a namespace and it disappears when the query finishes:

FeatureQL
SELECT
    FEATURE1 := 1,  -- local.feature1
    FEATURE2 := 2,  -- local.feature2
    FEATURE3 := FEATURE1 + FEATURE2  -- local.feature3 := local.feature1 + local.feature2
;
Result
FEATURE1 BIGINTFEATURE2 BIGINTFEATURE3 BIGINT
123

Pulling features from a namespace

The FROM clause sets a namespace context. Unqualified feature names resolve against it, so you can reference persistent features without spelling out their full path.

First, let's create some features to work with:

FeatureQL
CREATE OR REPLACE FEATURES AS
SELECT
    10 AS FM.TUTORIALS.NAMESPACES.FEATURE1,
    20 AS FM.TUTORIALS.NAMESPACES.FEATURE2,
    100 AS FM.TUTORIALS.NAMESPACES.NS1.FEATURE1,
    200 AS FM.TUTORIALS.NAMESPACES.NS1.FEATURE2,
    1000 AS FM.TUTORIALS.NAMESPACES.NS2.FEATURE1,
    2000 AS FM.TUTORIALS.NAMESPACES.NS2.FEATURE2,
;
Result
feature_name VARCHARstatus VARCHARmessage VARCHAR
FM.TUTORIALS.NAMESPACES.FEATURE1CREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.FEATURE2CREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.NS1.FEATURE1CREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.NS1.FEATURE2CREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.NS2.FEATURE1CREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.NS2.FEATURE2CREATEDFeature created as not exists

Now reference them through the namespace:

FeatureQL
SELECT
    FEATUREA := FEATURE1 + 1,  -- local.featurea := fm.tutorials.namespaces.feature1 + literal
    FEATUREB := FEATURE1 + FEATURE2,  -- local.featureb := fm.tutorials.namespaces.feature1 + fm.tutorials.namespaces.feature2
FROM FM.TUTORIALS.NAMESPACES
;
Result
FEATUREA BIGINTFEATUREB BIGINT
1130

You can also alias namespace features directly in the SELECT clause:

FeatureQL
SELECT
    FEATURE1 AS F1,  -- fm.tutorials.namespaces.feature1
    FEATURE2 AS F2,  -- fm.tutorials.namespaces.feature2
FROM FM.TUTORIALS.NAMESPACES
;
Result
F1 BIGINTF2 BIGINT
1020

Mixing local and namespace features

Local definitions and namespace references work together in the same query. When a name collision occurs, local features win — a locally defined feature always takes precedence over a namespace feature with the same name.

FeatureQL
SELECT
    FEATUREA := FEATURE1 + 1,  -- local.featurea := fm.tutorials.namespaces.feature1 + literal
    FEATUREB := FEATURE1 + FEATURE2,  -- local.featureb := fm.tutorials.namespaces.feature1 + fm.tutorials.namespaces.feature2
    FEATUREC := FEATUREB + FEATURE1,  -- local.featurec := local.featureb + fm.tutorials.namespaces.feature1
FROM FM.TUTORIALS.NAMESPACES
;
Result
FEATUREA BIGINTFEATUREB BIGINTFEATUREC BIGINT
113040

Here, FEATURE1 is redefined locally as 1, so FEATUREB uses the local value instead of the namespace value (10):

FeatureQL
SELECT
    FEATURE1 := 1,  -- local.feature1 := literal
    FEATUREB := FEATURE1 + FEATURE2,  -- local.featureb := local.feature1 + fm.tutorials.namespaces.feature2
    FEATUREC := FEATUREB + FEATURE1,  -- local.featurec := local.featureb + local.feature1
FROM FM.TUTORIALS.NAMESPACES
;
Result
FEATURE1 BIGINTFEATUREB BIGINTFEATUREC BIGINT
12122

Aliases

When a query references multiple namespaces, aliases keep things readable. An alias is a short prefix (always starting with _) that maps to a namespace path.

FeatureQL
SELECT
    FEATURE1 := _a.FEATURE1,  -- local.feature1 := fm.tutorials.namespaces.feature1
    FEATURE2 := FEATURE1 + _a.NS1.FEATURE1  -- local.feature2 := local.feature1 + fm.tutorials.namespaces.ns1.feature1
FROM FM.TUTORIALS.NAMESPACES AS _a
;
Result
FEATURE1 BIGINTFEATURE2 BIGINT
10110

Multiple aliases

Use multiple aliases to pull features from different namespaces in the same query:

FeatureQL
SELECT
    FEATURE1 := _a.FEATURE1,  -- local.feature1 := fm.tutorials.namespaces.feature1
    FEATURE2 := FEATURE1 + _b.FEATURE1  -- local.feature2 := local.feature1 + fm.tutorials.namespaces.ns1.feature1
FROM FM.TUTORIALS.NAMESPACES AS _a, FM.TUTORIALS.NAMESPACES.NS1 AS _b
;
Result
FEATURE1 BIGINTFEATURE2 BIGINT
10110

Combining unnamed namespace, aliases, and local features

A query can have one unnamed namespace (from FROM), multiple aliases, and local features — all at once. FeatureQL resolves each reference using a clear priority: local first, then aliases, then the unnamed namespace.

FeatureQL
SELECT
    FEATUREA := FEATURE1 + _a.FEATURE1 + _b.FEATURE1,  -- local.featurea := fm.tutorials.namespaces.feature1 + fm.tutorials.namespaces.ns1.feature1 + fm.tutorials.namespaces.ns2.feature1
    FEATURE2 := 2,  -- local.feature2 := literal
    FEATUREB := FEATURE2 + _a.FEATURE2 + _b.FEATURE2,  -- local.featureb := local.feature2 + fm.tutorials.namespaces.ns1.feature2 + fm.tutorials.namespaces.ns2.feature2
FROM
    FM.TUTORIALS.NAMESPACES,
    FM.TUTORIALS.NAMESPACES.NS1 AS _a,
    FM.TUTORIALS.NAMESPACES.NS2 AS _b
;
Result
FEATUREA BIGINTFEATURE2 BIGINTFEATUREB BIGINT
111022202

Creating persistent features

CREATE FEATURES IN stores new features in a specific namespace:

FeatureQL
CREATE FEATURES IN FM.TUTORIALS.NAMESPACES AS
SELECT
    CREATED_FEATURE1 := 11,  -- fm.tutorials.namespaces.created_feature1 := literal
    CREATED_FEATURE2 := CREATED_FEATURE1 + 10  -- fm.tutorials.namespaces.created_feature2 := fm.tutorials.namespaces.created_feature1 + literal
;
Result
feature_name VARCHARstatus VARCHARmessage VARCHAR
FM.TUTORIALS.NAMESPACES.CREATED_FEATURE2CREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.CREATED_FEATURE1CREATEDFeature created as not exists

You can combine CREATE FEATURES IN with FROM and aliases to build derived features that reference multiple existing namespaces:

FeatureQL
CREATE FEATURES IN FM.TUTORIALS.NAMESPACES.NS3 AS
SELECT
    FEATUREA := _0.FEATURE1 + _a.FEATURE1 + _b.FEATURE1,  -- fm.tutorials.namespaces.ns3.featurea := fm.tutorials.namespaces.feature1 + fm.tutorials.namespaces.ns1.feature1 + fm.tutorials.namespaces.ns2.feature1
    FEATURE2 := 2,  -- fm.tutorials.namespaces.ns3.feature2 := literal
    FEATUREB := _0.FEATURE2 + _a.FEATURE2 + _0.NS2.FEATURE2,  -- fm.tutorials.namespaces.ns3.featureb := fm.tutorials.namespaces.feature2 + fm.tutorials.namespaces.ns1.feature2 + fm.tutorials.namespaces.ns2.feature2
    FEATUREC := FEATURE2 + FEATUREA + FEATUREB  -- fm.tutorials.namespaces.ns3.featurec := fm.tutorials.namespaces.ns3.feature2 + fm.tutorials.namespaces.ns3.featurea + fm.tutorials.namespaces.ns3.featureb
FROM
    FM.TUTORIALS.NAMESPACES AS _0,
    FM.TUTORIALS.NAMESPACES.NS1 AS _a,
    FM.TUTORIALS.NAMESPACES.NS2 AS _b
;
Result
feature_name VARCHARstatus VARCHARmessage VARCHAR
FM.TUTORIALS.NAMESPACES.NS3.FEATUREACREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.NS3.FEATUREBCREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.NS3.FEATURECCREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.NS3.FEATURE2CREATEDFeature created as not exists

USE statements

The USE statement sets a default namespace for all subsequent queries in a multi-statement session, replacing the need for an unnamed namespace in FROM:

FeatureQL
USE FM.TUTORIALS.NAMESPACES;
SELECT
    FEATUREA := FEATURE1 + _a.FEATURE1 + _b.FEATURE1,  -- local.featurea := fm.tutorials.namespaces.feature1 + fm.tutorials.namespaces.ns1.feature1 + fm.tutorials.namespaces.ns2.feature1
    FEATURE2 := 2,  -- local.feature2 := literal
    FEATUREB := FEATURE2 + _a.FEATURE2 + _b.FEATURE2,  -- local.featureb := local.feature2 + fm.tutorials.namespaces.ns1.feature2 + fm.tutorials.namespaces.ns2.feature2
FROM
    FM.TUTORIALS.NAMESPACES.NS1 AS _a,
    FM.TUTORIALS.NAMESPACES.NS2 AS _b
;
Result
FEATUREA BIGINTFEATURE2 BIGINTFEATUREB BIGINT
111022202

USE also works with WITH clauses, aliases, and qualified references. Features defined in WITH are always local, regardless of any CREATE FEATURES IN context:

FeatureQL
USE FM.TUTORIALS.NAMESPACES;
WITH
    FEATUREA := FEATURE1 + _a.FEATURE1 + _b.FEATURE1,  -- local.featurea := fm.tutorials.namespaces.feature1 + fm.tutorials.namespaces.ns1.feature1 + fm.tutorials.namespaces.ns2.feature1
    FEATURE2 := 2,  -- local.feature2 := literal (WITH always creates local)
    FEATUREB := FEATURE2 + _a.FEATURE2 + NS2.FEATURE2,  -- local.featureb := local.feature2 + fm.tutorials.namespaces.ns1.feature2 + fm.tutorials.namespaces.ns2.feature2
SELECT
    FEATUREA,  -- local.featurea
    FEATUREB,  -- local.featureb
    FEATUREC := FEATURE2 + FEATUREA + FEATUREB  -- local.featurec := local.feature2 + local.featurea + local.featureb
FROM
    FM.TUTORIALS.NAMESPACES.NS1 AS _a,
    FM.TUTORIALS.NAMESPACES.NS2 AS _b
;
Result
FEATUREA BIGINTFEATUREB BIGINTFEATUREC BIGINT
111022023314

Name resolution rules

FeatureQL resolves feature names in a predictable order:

  1. Validation — Names cannot start with _ (reserved for aliases). No duplicate definitions. Only one unnamed namespace per statement.
  2. Fully qualified names — Names starting with fm. are never modified.
  3. Alias resolution_alias.FEATURE expands to the full namespace path.
  4. Created features — New features go to the CREATE FEATURES IN namespace, or stay local.
  5. Reference resolution — Check local features first, then the unnamed namespace from FROM.

Error handling

FeatureQL catches namespace mistakes early with clear error messages.

Feature names cannot start with _ (that's alias syntax):

FeatureQL
SELECT _BADFEATURE := 1;  -- ERROR: feature names cannot start with underscore
Result
ERROR UE/FEATURE_NAME_UNDERSCORE Feature name cannot start with underscore: _BADFEATURE

Referencing an undefined alias fails immediately:

FeatureQL
SELECT FEATURE1 := _unknown.SOME_FEATURE;  -- ERROR: _unknown alias not defined
Result
ERROR UE/ALIAS_NOT_FOUND Alias not found: _UNKNOWN

Multiple unnamed namespaces are ambiguous — FeatureQL rejects them when you reference features that need resolution:

FeatureQL
SELECT FEATURE1 FROM FM.TUTORIALS.NS1, FM.TUTORIALS.NS2;  -- ERROR: ambiguous FEATURE1 resolution (???.feature1)
Result
ERROR UE/MULTIPLE_UNNAMED_NAMESPACES Multiple unnamed namespaces not allowed: FM.TUTORIALS.NS1, FM.TUTORIALS.NS2

The same rule applies when USE conflicts with an unnamed FROM namespace:

FeatureQL
USE FM.TUTORIALS.NAMESPACES;
SELECT
    FEATUREA := FEATURE1 + FEATURE2,  -- ERROR: ambiguous namespace resolution (???.featurea := ???.feature1 + ???.feature2)
FROM FM.TUTORIALS.NAMESPACES.NS2
;
Result
ERROR UE/MULTIPLE_UNNAMED_NAMESPACES Multiple unnamed namespaces not allowed: FM.TUTORIALS.NAMESPACES, FM.TUTORIALS.NAMESPACES.NS2

Namespaces must start with fm.:

FeatureQL
CREATE FEATURES IN invalid.namespace AS SELECT FEATURE1 := 1;  -- ERROR: namespace must start with fm.
Result
ERROR UE/INVALID_NAMESPACE_NAME Namespace not starting with FM. so invalid: INVALID.NAMESPACE

Edge case

If all features in a multi-namespace query are locally defined (not referencing the namespace), the ambiguity doesn't trigger — there's nothing to resolve:

FeatureQL
SELECT FEATURE1:=1 FROM FM.TUTORIALS.NS1, FM.TUTORIALS.NS2;  -- local.feature1 := literal (works because creating local)
Result
FEATURE1 BIGINT
1

Best practices

  • Use descriptive hierarchies: fm.user_analytics.daily_metrics.click_rate beats fm.feature1. Organize by domain, team, or project.
  • Choose meaningful aliases: _users, _products, _txns — not _a, _b, _c.
  • Be explicit in complex queries: When multiple namespaces are in play, fully qualified names prevent surprises.
  • Group related features: Keep features that belong together in the same namespace subtree.
Last update at: 2026/03/03 16:47:38
Last updated: 2026-03-03 16:48:19