Redis data sources

EXTERNAL_REDIS() connects FeatureQL to Redis instances for low-latency feature retrieval. Redis is typically the fastest option for real-time serving — ideal for cached profiles, feature flags, and precomputed aggregates.

Creating a Redis source

Before querying Redis, create a persistent connection with SOURCE_REDIS():

FeatureQL
CREATE OR REPLACE FEATURE FM.TUTORIALS.EXTERNAL.REDIS_SRC AS
    SOURCE_REDIS(
        'redis://host.docker.internal:6380'
        WITH (
            timeout='500ms',
            key_patterns=ARRAY['customer_hash:*']
        )
    );
Result
feature_name VARCHARstatus VARCHARmessage VARCHAR
FM.TUTORIALS.EXTERNAL.REDIS_SRCCREATEDFeature created as not exists

The connection string follows the standard redis://host:port format. The timeout parameter controls both connection and operation timeouts. key_patterns is an optimization hint that tells FeatureMesh which keys this source will access.

JSON key retrieval

The simplest pattern fetches a Redis key containing a JSON object, then parses it into a typed row:

FeatureQL
WITH
    CUSTOMER_ID := INPUT(BIGINT),
    CUSTOMER_DETAILS_JSON := EXTERNAL_REDIS(KEY 'customer:' || CUSTOMER_ID::VARCHAR FROM FM.TUTORIALS.EXTERNAL.REDIS_SRC),
    CUSTOMER_DETAILS := JSON_PARSE_AS(CUSTOMER_DETAILS_JSON, TYPE 'ROW(customer_id BIGINT, email VARCHAR, last_order_id BIGINT)'),
SELECT
    CUSTOMER_ID := BIND_VALUES(ARRAY[1,3,5,7]),
    LAST_ORDER_ID := CUSTOMER_DETAILS[last_order_id]
ORDER BY CUSTOMER_ID;
Result
CUSTOMER_ID BIGINTLAST_ORDER_ID BIGINT
11
3492020
2271134
3394992

The key expression 'customer:' || CUSTOMER_ID::VARCHAR builds a dynamic key per input. EXTERNAL_REDIS(KEY ...) returns the raw JSON string, and JSON_PARSE_AS() converts it to a structured row with type safety. From there, bracket notation extracts individual fields like CUSTOMER_DETAILS[last_order_id].

This pattern works well for complex objects — customer profiles, product catalogs, configuration records.

Hash field access

When your data lives in Redis hashes, you can skip JSON parsing entirely and fetch individual fields directly:

FeatureQL
WITH
    CUSTOMER_ID := INPUT(BIGINT)
SELECT
    CUSTOMER_ID := BIND_VALUES(ARRAY[1,3,5,7]),
    LAST_ORDER_ID := EXTERNAL_REDIS(KEY 'customer_hash:' || CUSTOMER_ID::VARCHAR FIELD 'last_order_id' FROM FM.TUTORIALS.EXTERNAL.REDIS_SRC)
ORDER BY CUSTOMER_ID;
Result
CUSTOMER_ID BIGINTLAST_ORDER_ID BIGINT
11
3492020
2271134
3394992

The FIELD keyword tells FeatureQL to issue an HGET instead of a GET. This is more efficient than fetching the entire object when you only need one or two fields — less data over the wire, no parsing overhead.

Table-style access with EXTERNAL_VIEW()

For more advanced patterns, EXTERNAL_VIEW() treats Redis keys as rows in a virtual table. This lets you join on the key itself:

FeatureQL
WITH
    CUSTOMER_ID := INPUT(BIGINT),
    REDIS_VIEW := EXTERNAL_VIEW(
        `SELECT key, customer_id, last_order_id FROM %FM.TUTORIALS.EXTERNAL.REDIS_SRC[customer_hash:*]`  /* We need the "key" here */
        ON `SELF.key='customer_hash:' || %CUSTOMER_ID`
        AS ROW(key VARCHAR, customer_id BIGINT, last_order_id BIGINT)
    ),
SELECT
    CUSTOMER_ID := BIND_VALUES(ARRAY[1,2,3,4]),
    LAST_ORDER_ID := REDIS_VIEW[last_order_id]
ORDER BY CUSTOMER_ID;
Result
CUSTOMER_ID BIGINTLAST_ORDER_ID BIGINT
11
3492020
2271134
3394992

Or join on field values within the hashes:

FeatureQL
WITH
    CUSTOMER_ID := INPUT(BIGINT),
    REDIS_VIEW := EXTERNAL_VIEW(
        `SELECT key, customer_id, last_order_id FROM %FM.TUTORIALS.EXTERNAL.REDIS_SRC[customer_hash:*]`  /* We need the "key" here */
        ON `SELF.key='customer_hash:' || %CUSTOMER_ID`
        AS ROW(key VARCHAR, customer_id BIGINT, last_order_id BIGINT)
    ),
SELECT
    CUSTOMER_ID := BIND_VALUES(ARRAY[1,2,3,4]),
    LAST_ORDER_ID := REDIS_VIEW[last_order_id]
ORDER BY CUSTOMER_ID;
Result
CUSTOMER_ID BIGINTLAST_ORDER_ID BIGINT
11
3492020
2271134
3394992

Performance

Table-style access scans all keys matching the pattern. Reserve this for small datasets — it is significantly slower than direct key or hash field lookups.

Error handling

Redis operations return NULL when they fail — whether from network issues, missing keys, timeouts, or JSON parsing errors. Use COALESCE() to provide fallback values:

CUSTOMER_TIER := COALESCE(
    EXTERNAL_REDIS(KEY 'customer_hash:' || CUSTOMER_ID::VARCHAR FIELD 'tier' FROM REDIS_SRC),
    'standard'
)
sql
Last update at: 2026/03/03 16:47:38
Last updated: 2026-03-03 16:48:19