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:
SELECT customer_id, last_order_id
FROM serving_slt_federated_customers
ORDER BY customer_id;| CUSTOMER_ID BIGINT | LAST_ORDER_ID BIGINT |
|---|---|
| 1 | 101 |
| 2 | 202 |
MGET serving_slt:order:101 serving_slt:order:202| 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:
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')
)
;| feature_name VARCHAR | status VARCHAR | message VARCHAR |
|---|---|---|
| FM.TUTORIALS.FEDERATED.POSTGRES_CONN | CREATED | Feature created as not exists |
| FM.TUTORIALS.FEDERATED.REDIS_SRC | CREATED | Feature created as not exists |
Then install both definitions in the local serving process with one explicit refresh:
REFRESH FEATURES
FM.TUTORIALS.FEDERATED.POSTGRES_CONN,
FM.TUTORIALS.FEDERATED.REDIS_SRC
;| FEATURE VARCHAR | KIND VARCHAR | STATUS VARCHAR | MESSAGE VARCHAR |
|---|---|---|---|
| FM.TUTORIALS.FEDERATED.POSTGRES_CONN | SOURCE_JDBC | REFRESHED | (empty) |
| FM.TUTORIALS.FEDERATED.REDIS_SRC | SOURCE_REDIS | REFRESHED | (empty) |
Combining Redis and PostgreSQL
This query retrieves customer data from PostgreSQL and enriches it with order details from Redis:
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
;| CUSTOMER_ID BIGINT | LAST_ORDER_PRICE DECIMAL |
|---|---|
| 1 | 19.99 |
| 2 | 12.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.