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:
RETURN
feature1 := 1, -- local.feature1
feature2 := 2, -- local.feature2
feature3 := feature1
+ feature2 -- local.feature3 := local.feature1 + local.feature2
;| FEATURE1 BIGINT | FEATURE2 BIGINT | FEATURE3 BIGINT |
|---|---|---|
| 1 | 2 | 3 |
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:
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
;| feature_name VARCHAR | status VARCHAR | message VARCHAR |
|---|---|---|
| FM.TUTORIALS.NAMESPACES.FEATURE1 | CREATED | Feature created as not exists |
| FM.TUTORIALS.NAMESPACES.FEATURE2 | CREATED | Feature created as not exists |
| FM.TUTORIALS.NAMESPACES.NS1.FEATURE1 | CREATED | Feature created as not exists |
| FM.TUTORIALS.NAMESPACES.NS1.FEATURE2 | CREATED | Feature created as not exists |
| FM.TUTORIALS.NAMESPACES.NS2.FEATURE1 | CREATED | Feature created as not exists |
| FM.TUTORIALS.NAMESPACES.NS2.FEATURE2 | CREATED | Feature created as not exists |
Now use its persisted features through the default namespace:
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
;| FEATUREA BIGINT | FEATUREB BIGINT |
|---|---|
| 11 | 30 |
AS can give selected outputs shorter names. This renames the result columns; it does not create a namespace alias:
RETURN
f1 := feature1, -- fm.tutorials.namespaces.feature1
f2 := feature2, -- fm.tutorials.namespaces.feature2
FROM FM.TUTORIALS.NAMESPACES
;| F1 BIGINT | F2 BIGINT |
|---|---|
| 10 | 20 |
Mixing local and namespace features
Local definitions and persisted references can appear in the same query:
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
;| FEATUREA BIGINT | FEATUREB BIGINT | FEATUREC BIGINT |
|---|---|---|
| 11 | 30 | 40 |
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:
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
;| FEATURE1 BIGINT | FEATUREB BIGINT | FEATUREC BIGINT |
|---|---|---|
| 1 | 21 | 22 |
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:
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
;| FEATURE1 BIGINT | FEATURE2 BIGINT |
|---|---|
| 10 | 110 |
Multiple aliases
Use multiple aliases to pull features from different namespaces in the same query:
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
;| FEATURE1 BIGINT | FEATURE2 BIGINT |
|---|---|
| 10 | 110 |
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.
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
;| FEATUREA BIGINT | FEATURE2 BIGINT | FEATUREB BIGINT |
|---|---|---|
| 1110 | 2 | 2202 |
Target a namespace when creating features
CREATE FEATURES IN stores every selected feature in one namespace, so the individual feature names can stay short:
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
;| feature_name VARCHAR | status VARCHAR | message VARCHAR |
|---|---|---|
| FM.TUTORIALS.NAMESPACES.CREATED_FEATURE1 | CREATED | Feature created as not exists |
| FM.TUTORIALS.NAMESPACES.CREATED_FEATURE2 | CREATED | Feature created as not exists |
The create statement can also read from aliased namespaces while writing to a different target namespace:
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
;| feature_name VARCHAR | status VARCHAR | message VARCHAR |
|---|---|---|
| FM.TUTORIALS.NAMESPACES.NS3.FEATUREA | CREATED | Feature created as not exists |
| FM.TUTORIALS.NAMESPACES.NS3.FEATURE2 | CREATED | Feature created as not exists |
| FM.TUTORIALS.NAMESPACES.NS3.FEATUREB | CREATED | Feature created as not exists |
| FM.TUTORIALS.NAMESPACES.NS3.FEATUREC | CREATED | Feature 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:
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
;| FEATUREA BIGINT | FEATURE2 BIGINT | FEATUREB BIGINT |
|---|---|---|
| 1110 | 2 | 2202 |
USE also works with DEFINE, aliases, and fully qualified references. Features defined in DEFINE remain local:
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
;| FEATUREA BIGINT | FEATUREB BIGINT | FEATUREC BIGINT |
|---|---|---|
| 1110 | 2202 | 3314 |
Name resolution rules
Read a name from left to right:
- A name beginning with
FM.is already fully qualified. - A name beginning with
_alias.expands through the matching alias. - An unqualified name resolves to a local feature when one exists.
- Otherwise, an unqualified name resolves inside the default namespace from
FROMorUSE. - 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):
RETURN _BADFEATURE := 1; -- ERROR: feature names cannot start with underscoreReferencing an undefined alias fails immediately:
RETURN FEATURE1 := _unknown.SOME_FEATURE -- ERROR: _unknown alias not defined
;Multiple default namespaces are ambiguous and therefore invalid:
RETURN FEATURE1 -- ERROR: ambiguous FEATURE1 resolution (???.feature1)
FROM FM.TUTORIALS.NS1, FM.TUTORIALS.NS2
;The same rule applies when USE conflicts with an unaliased namespace in FROM:
USE fm.tutorials.namespaces;
RETURN
featurea := feature1 + feature2, -- ERROR: ambiguous namespace resolution (???.featurea := ???.feature1 + ???.feature2)
FROM FM.TUTORIALS.NAMESPACES.NS2
;Namespaces must start with fm.:
CREATE FEATURES IN invalid.namespace AS PERSIST FEATURE1 := 1 -- ERROR: namespace must start with fm.
;Validation happens at statement level, so multiple unaliased namespaces are rejected even when the query body defines only local features:
RETURN
feature1 := 1
FROM
FM.TUTORIALS.NS1,
FM.TUTORIALS.NS2
;Best practices
- Use descriptive hierarchies:
FM.USER_ANALYTICS.DAILY_METRICS.CLICK_RATEbeatsFM.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 .