Multi-source queries

The previous pages each covered a single connector — Redis, JDBC, HTTP. In practice, the data you need for a feature often lives in more than one system. FeatureQL lets you mix connectors freely in a single query: look up a customer in PostgreSQL, fetch their latest order from Redis, and combine the results — all without writing any orchestration code.

Inspect the source fixtures directly

Named SLT executors can run queries against each external store and assert their results before FeatureQL uses them:

Postgres
SELECT customer_id, last_order_id
FROM serving_slt_federated_customers
ORDER BY customer_id;
Result
CUSTOMER_ID BIGINTLAST_ORDER_ID BIGINT
1101
2202

Redis
MGET serving_slt:order:101 serving_slt:order:202
Result
ORDER_DETAILS VARCHAR
{"order_id":101,"price":19.99}
{"order_id":202,"price":12.74}

Configure both sources

Persist the PostgreSQL and Redis connections together:

FeatureQL
CREATE OR REPLACE FEATURES IN FM.TUTORIALS.FEDERATED AS
SELECT
    POSTGRES_CONN := SOURCE_JDBC(
        'postgresql://featuremesh:featuremesh@host.docker.internal:5433/featuremesh?sslmode=disable'
        WITH (
            tables=ARRAY['serving_slt_federated_customers'],
            timeout='500ms'
        )
    ),
    REDIS_SRC := SOURCE_REDIS(
        'redis://host.docker.internal:6380'
        WITH (timeout='500ms')
    )
;
Result
feature_name VARCHARstatus VARCHARmessage VARCHAR
FM.TUTORIALS.FEDERATED.POSTGRES_CONNCREATEDFeature created as not exists
FM.TUTORIALS.FEDERATED.REDIS_SRCCREATEDFeature created as not exists

Then install both definitions in the local serving process with one explicit refresh:

FeatureQL
REFRESH FEATURES
    FM.TUTORIALS.FEDERATED.POSTGRES_CONN,
    FM.TUTORIALS.FEDERATED.REDIS_SRC
;
Result
FEATURE VARCHARKIND VARCHARSTATUS VARCHARMESSAGE VARCHAR
FM.TUTORIALS.FEDERATED.POSTGRES_CONNSOURCE_JDBCREFRESHED(empty)
FM.TUTORIALS.FEDERATED.REDIS_SRCSOURCE_REDISREFRESHED(empty)

Combining Redis and PostgreSQL

This query retrieves customer data from PostgreSQL and enriches it with order details from Redis:

FeatureQL
WITH
    ORDERS := ENTITY(),
    ORDER_ID := INPUT(BIGINT#ORDERS),
    REDIS_KEY := 'serving_slt:order:' || UNSAFE_CAST(ORDER_ID AS VARCHAR),
    ORDER_DETAILS_STR := EXTERNAL_REDIS(
        KEY REDIS_KEY
        FROM FM.TUTORIALS.FEDERATED.REDIS_SRC
    ),
    ORDER_DETAILS := JSON_PARSE_AS(
        ORDER_DETAILS_STR,
        TYPE 'ROW(order_id BIGINT, price DOUBLE)'
    ),
    CUSTOMERS := ENTITY(),
    CUSTOMER_ID := INPUT(BIGINT#CUSTOMERS),
    CUSTOMER_DETAILS := EXTERNAL_COLUMNS(
        customer_id BIGINT#CUSTOMERS BIND TO CUSTOMER_ID,
        last_order_id BIGINT#ORDERS
        FROM VIEW(FM.TUTORIALS.FEDERATED.POSTGRES_CONN[serving_slt_federated_customers])
    ),
    LAST_ORDER_ID := CUSTOMER_DETAILS[last_order_id],
    LAST_ORDER_JOIN := EXTEND(
        ROW(LAST_ORDER_ID AS last_order_id)
        WITH ORDER_DETAILS AS order_details
        VIA last_order_id BIND TO ORDER_ID
    ),
    LAST_ORDER_PRICE := LAST_ORDER_JOIN[order_details][price],
SELECT
    CUSTOMER_ID := BIND_VALUES(ARRAY[1, 2]),
    LAST_ORDER_PRICE
;
Result
CUSTOMER_ID BIGINTLAST_ORDER_PRICE DECIMAL
119.99
212.74

The query defines two entities backed by different data stores. CUSTOMERS lives in PostgreSQL (via EXTERNAL_COLUMNS()), ORDERS lives in Redis (via EXTERNAL_REDIS()). The EXTEND() call bridges the two: it takes the last_order_id from the PostgreSQL result and uses it to look up order data in Redis, linking them through the BIGINT#ORDERS entity annotation.

FeatureMesh resolves the dependency graph automatically — it knows to query PostgreSQL first (to get last_order_id), then Redis (to fetch the order details). Each source is queried using its native access pattern: parameterized SQL for PostgreSQL, key-based lookup for Redis.

How it works

There is no special syntax for multi-source queries. You simply define features that reference different connectors, and FeatureMesh figures out the execution order from the dependency graph. The same mechanisms that resolve feature dependencies within a single source work across sources.

This means any query you build with individual connectors can be extended to span multiple sources — just add more features that reference other connectors and link them through entity annotations or EXTEND().

Taking it to production

Once you have a multi-source query working, you can compile it into a prepared statement for production serving. The prepared statement captures the entire dependency graph — including all cross-source joins — into a single pre-compiled unit. Clients call it with just the input values, and FeatureMesh handles the rest.