Namespaces & aliases

Namespaces organize persisted features into paths such as FM.USER_ANALYTICS.DAILY_CLICKS. This page explains how to choose those paths, shorten them with aliases, and predict which feature an unqualified name will resolve to.

Persistent vs. local features

A local feature belongs only to the current query. A persisted feature is stored in the registry under a fully qualified name beginning with FM..

Feature definitions are local by default. In this query, all three features disappear when the query finishes:

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

To persist a definition, publish it with CREATE FEATURE or CREATE FEATURES. See Create features after learning how names resolve.

Use a default namespace

FROM <namespace> sets the default namespace for one statement. FeatureQL looks there when an unqualified name does not refer to a local feature, so you do not have to repeat the full FM. path.

First, create a small namespace to explore:

FeatureQL
CREATE OR REPLACE FEATURES AS
PERSIST
    fm.tutorials.namespaces.feature1 := 10,
    fm.tutorials.namespaces.feature2 := 20,
    fm.tutorials.namespaces.ns1.feature1 := 100,
    fm.tutorials.namespaces.ns1.feature2 := 200,
    fm.tutorials.namespaces.ns2.feature1 := 1000,
    fm.tutorials.namespaces.ns2.feature2 := 2000
;
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 use its persisted features through the default namespace:

FeatureQL
RETURN
    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

AS can give selected outputs shorter names. This renames the result columns; it does not create a namespace alias:

FeatureQL
RETURN
    f1 := feature1, -- fm.tutorials.namespaces.feature1
    f2 := feature2, -- fm.tutorials.namespaces.feature2
FROM FM.TUTORIALS.NAMESPACES
;
Result
F1 BIGINTF2 BIGINT
1020

Mixing local and namespace features

Local definitions and persisted references can appear in the same query:

FeatureQL
RETURN
    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

When a local feature and the default namespace contain the same unqualified name, direct references in the query use the local feature. Here, FEATURE1 is local, so FEATUREB uses 1 rather than the persisted value 10:

FeatureQL
RETURN
    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

This does not rewrite the dependency graph of other persisted features. To override a persisted definition and make its dependents recompute, assign to its fully qualified FM. name; Select persisted features shows that workflow.

Use aliases for multiple namespaces

When a query references multiple namespaces, give each namespace an alias in FROM. Alias names start with _, which keeps them visually distinct from features:

FeatureQL
RETURN
    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
RETURN
    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 combine one default namespace, multiple aliased namespaces, and local features. Unqualified names use local definitions first and then the default namespace; qualified _alias.FEATURE references always use the aliased namespace.

FeatureQL
RETURN
    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

Target a namespace when creating features

CREATE FEATURES IN stores every selected feature in one namespace, so the individual feature names can stay short:

FeatureQL
CREATE FEATURES IN FM.TUTORIALS.NAMESPACES AS
PERSIST
    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_FEATURE1CREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.CREATED_FEATURE2CREATEDFeature created as not exists

The create statement can also read from aliased namespaces while writing to a different target namespace:

FeatureQL
CREATE FEATURES IN FM.TUTORIALS.NAMESPACES.NS3 AS
PERSIST
    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.FEATURE2CREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.NS3.FEATUREBCREATEDFeature created as not exists
FM.TUTORIALS.NAMESPACES.NS3.FEATURECCREATEDFeature created as not exists

For creation variants and replacement behavior, see Create features .

Keep a default with USE

USE sets the default namespace for the following statements in the same multi-statement request. Use it when several statements work in the same namespace:

FeatureQL
USE fm.tutorials.namespaces;
RETURN
    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 DEFINE, aliases, and fully qualified references. Features defined in DEFINE remain local:

FeatureQL
USE fm.tutorials.namespaces;
DEFINE
    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 (DEFINE always creates local)
    featureb := feature2 + _a.feature2 + ns2.feature2, -- local.featureb := local.feature2 + fm.tutorials.namespaces.ns1.feature2 + fm.tutorials.namespaces.ns2.feature2
RETURN
    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

Read a name from left to right:

  1. A name beginning with FM. is already fully qualified.
  2. A name beginning with _alias. expands through the matching alias.
  3. An unqualified name resolves to a local feature when one exists.
  4. Otherwise, an unqualified name resolves inside the default namespace from FROM or USE.
  5. In CREATE FEATURES IN, unqualified output names are written into the target namespace.

Feature names cannot start with _, aliases must be declared, and a statement can have only one default namespace.

Error handling

FeatureQL rejects ambiguous or invalid names before evaluation.

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

FeatureQL
RETURN _BADFEATURE := 1;  -- ERROR: feature names cannot start with underscore
Result
ERROR UE/FEATURE-NAME-UNDERSCORE Feature names must not start with an underscore (reserved for namespace aliases); got '_BADFEATURE'.

Referencing an undefined alias fails immediately:

FeatureQL
RETURN FEATURE1 := _unknown.SOME_FEATURE -- ERROR: _unknown alias not defined
;
Result
ERROR UE/ALIAS-NOT-FOUND Namespace alias '_UNKNOWN' is not declared in USE or FROM for this statement; declare it before using _alias.feature references.

Multiple default namespaces are ambiguous and therefore invalid:

FeatureQL
RETURN FEATURE1 -- ERROR: ambiguous FEATURE1 resolution (???.feature1)
FROM FM.TUTORIALS.NS1, FM.TUTORIALS.NS2
;
Result
ERROR UE/MULTIPLE-UNNAMED-NAMESPACES A multistatement may have at most one namespace without an alias; got 2: FM.TUTORIALS.NS1, FM.TUTORIALS.NS2

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

FeatureQL
USE fm.tutorials.namespaces;
RETURN
    featurea := feature1 + feature2, -- ERROR: ambiguous namespace resolution (???.featurea := ???.feature1 + ???.feature2)
FROM FM.TUTORIALS.NAMESPACES.NS2
;
Result
ERROR UE/MULTIPLE-UNNAMED-NAMESPACES A multistatement may have at most one namespace without an alias; got 2: FM.TUTORIALS.NAMESPACES, FM.TUTORIALS.NAMESPACES.NS2

Namespaces must start with fm.:

FeatureQL
CREATE FEATURES IN invalid.namespace AS PERSIST FEATURE1 := 1 -- ERROR: namespace must start with fm.
;
Result
ERROR UE/INVALID-NAMESPACE-NAME Namespace names must start with 'FM.'; got 'INVALID.NAMESPACE'.

Validation happens at statement level, so multiple unaliased namespaces are rejected even when the query body defines only local features:

FeatureQL
RETURN
    feature1 := 1
FROM
    FM.TUTORIALS.NS1,
    FM.TUTORIALS.NS2
;
Result
ERROR UE/MULTIPLE-UNNAMED-NAMESPACES A multistatement may have at most one namespace without an alias; got 2: FM.TUTORIALS.NS1, FM.TUTORIALS.NS2

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.

Next

Continue with Create features to publish a local definition into the registry. For multi-statement namespace context, see the USE syntax reference .