{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is a real-time feature store in 2026?",
"acceptedAnswer": {
"@type": "Answer",
"text": "A real-time feature store in 2026 is a system that computes ML features continuously from live event streams and serves them with sub-second freshness. Traditional feature stores like Feast and Tecton were optimized for batch training pipelines, where features are computed on a schedule and written to an online store like Redis or DynamoDB. A streaming feature store eliminates the batch computation step by using a streaming SQL engine to maintain features incrementally as each source event arrives, making features available within milliseconds of the underlying data changing."
}
},
{
"@type": "Question",
"name": "What happened to Tecton in 2025?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Tecton was acquired by Databricks in 2025. This pushed many teams evaluating commercial feature stores to reconsider their options, particularly those who were not already deep in the Databricks ecosystem. The acquisition accelerated interest in open-source and infrastructure-native alternatives like Feast and RisingWave-based feature pipelines."
}
},
{
"@type": "Question",
"name": "Can RisingWave replace a feature store like Feast or Tecton?",
"acceptedAnswer": {
"@type": "Answer",
"text": "RisingWave can replace the online feature serving layer and the streaming feature computation layer that Feast and Tecton provide. It cannot replace feature store capabilities like feature discovery catalogs, lineage tracking, or access control policies. For teams whose primary need is fresh feature computation and serving -- especially agent features with sub-second freshness requirements -- RisingWave provides a simpler architecture than the offline store plus online store split that Feast and Tecton are built around."
}
},
{
"@type": "Question",
"name": "Why do AI agents need features fresher than batch schedules?",
"acceptedAnswer": {
"@type": "Answer",
"text": "AI agents in 2026 make decisions and take actions autonomously: approving a transaction, generating a personalized offer, routing a support ticket, adjusting a price. The features those decisions depend on -- account activity in the last 15 minutes, current inventory levels, recent user behavior -- must reflect the current state of the world, not the state from the last hourly batch run. An agent making a credit decision with features that are 45 minutes stale may approve a user who has spent beyond their limit in the intervening time."
}
},
{
"@type": "Question",
"name": "How does streaming SQL eliminate training-serving skew?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Training-serving skew happens when the code computing features for model training differs from the code computing features at serving time. In traditional architectures, training reads from a data warehouse using PySpark or SQL, while serving reads pre-computed values from Redis or DynamoDB. These two paths diverge in subtle ways -- different join semantics, different null handling, different window boundary definitions. With streaming SQL, you define features once as materialized views. Serving reads the live view; training reads a historical export from the same view. The computation logic is identical, eliminating skew by construction."
}
}
]
}
Feature stores were built for a world where ML pipelines ran on schedules. A Spark job computed features every hour, wrote them to Redis, and the model read from Redis at inference time. This worked well enough for slowly changing features -- account age, lifetime purchase count, demographic attributes. It worked poorly for features that needed to be fresh.
In 2026, the failure mode has become more acute. AI agents are now deployed in production at organizations of every size. These agents make real decisions -- approve or deny a transaction, generate a personalized recommendation, adjust a price, route a support request. The features those decisions depend on cannot be 45 minutes stale. They need to reflect what happened in the last few seconds.
This article explains why traditional feature stores struggle with this requirement, how streaming SQL materialized views address it, and when the older tools are still the right answer.
What a Feature Store Actually Does
Before comparing approaches, it helps to be precise about what a feature store provides.
A feature store has two distinct functions:
Offline store: Historical features for model training. When a data scientist trains a model, they need feature values at the exact time each training sample was generated -- not today's feature values, but the values that existed when the label was assigned. The offline store is typically a columnar data warehouse (BigQuery, Snowflake, a data lake) that supports point-in-time feature lookups for training data generation.
Online store: Fresh features for model inference at serving time. When a model runs in production, it needs the current value of each feature for the entity being scored. The online store is typically Redis, DynamoDB, or another low-latency key-value store. Features are pre-computed and written there on a schedule; the serving layer reads by entity key.
The challenge that traditional feature stores face is keeping the online store fresh without requiring a full batch recomputation on every event. The usual answer is a streaming pipeline -- Kafka consumers that update the online store as events arrive. Feast supports this. Tecton has a similar capability. But streaming support is an add-on to tools originally designed for batch, and it shows in the operational complexity.
The Batch-Era Problem
The classic feature store pipeline looks like this:
- Raw events land in a data lake or warehouse
- A batch job (Spark, dbt, or similar) runs on a schedule -- hourly, daily
- Computed features are written to the offline store for training
- A separate process syncs a subset of features to the online store (Redis, DynamoDB)
- The model serving layer reads from the online store at inference time
This pipeline has three compounding problems for use cases that need freshness.
The freshness gap is the accuracy gap. For fraud detection, dynamic pricing, and real-time personalization, a feature value that is 30 to 60 minutes old is not a stale label -- it is wrong signal. A transaction velocity feature that was computed an hour ago tells you nothing about whether the last 15 minutes of activity are anomalous.
The offline/online split creates training-serving skew. Training features are computed by one code path; serving features are computed by another. Even with careful engineering, subtle differences accumulate: different join semantics, different null handling, different event-time window cutoffs. The model trains on a feature distribution that does not match what it sees in production. Model performance degrades without obvious errors to investigate.
Operational complexity scales with feature count. Each feature family needs a batch computation job, a streaming sync pipeline (if freshness matters), monitoring on the batch schedule, monitoring on the streaming lag, and backfill logic for both. At 20 features this is manageable. At 200 features across 15 models, it is a full-time operational burden.
What 2026 Changed
Three shifts have made the batch-era architecture harder to defend for new projects.
AI agents raised freshness requirements. An ML model that runs once per user session can tolerate hourly feature staleness because the session itself provides temporal context. An AI agent that runs continuously, making decisions on every event as it arrives, cannot. If an agent is deciding whether to approve a transaction, the feature "number of transactions in the last 15 minutes" must reflect what happened in the last 15 minutes -- not the last hour. The agent feature freshness requirement is an order of magnitude stricter than traditional model inference.
Tecton's acquisition by Databricks in 2025 reshuffled the commercial options. Tecton was the most mature commercial feature store for real-time use cases. After the Databricks acquisition, teams not already in the Databricks ecosystem began evaluating alternatives. This accelerated interest in open-source Feast and infrastructure-native approaches.
Streaming SQL databases became operationally viable. RisingWave, which is Apache 2.0 open source, provides PostgreSQL wire protocol compatibility, incremental materialized views, and native CDC connectors. The operational model -- define sources and views in SQL, query over psql -- is simpler than the multi-component architecture of traditional feature stores. For new projects starting in 2026, the cost of the offline/online split is harder to justify when one streaming SQL system can handle both.
Why Streaming SQL Changes the Architecture
The traditional architecture requires three distinct systems: a batch compute engine (Spark), an offline store (data warehouse), and an online store (Redis or DynamoDB). Features move through this chain on a schedule.
The streaming SQL architecture with RisingWave works differently:
- Change data capture or Kafka events flow into RisingWave
- Materialized views compute features incrementally -- every event updates the relevant view rows
- The serving layer connects via PostgreSQL protocol and queries the view directly
No separate online store. No batch schedule. No sync pipeline. The materialized view is the online store, and it updates within milliseconds of each source event.
This is only practical if the serving layer latency is acceptable. Because RisingWave maintains pre-computed materialized view results, queries return in single-digit milliseconds regardless of how many raw events the system has processed. This matches Redis latency for most feature serving use cases.
Building the Feature Store in SQL
The following SQL creates a complete streaming feature store for user behavior, activity velocity, and account risk features. It runs on RisingWave.
User activity features from Kafka
Connect RisingWave to a Kafka topic carrying user events:
CREATE SOURCE user_events_source (
event_id TEXT,
user_id TEXT,
event_type TEXT,
amount DECIMAL,
item_id TEXT,
session_id TEXT,
event_time TIMESTAMPTZ
) WITH (
connector = 'kafka',
topic = 'user-events',
properties.bootstrap.server = 'kafka:9092',
scan.startup.mode = 'latest'
) FORMAT PLAIN ENCODE JSON;
CREATE TABLE user_events (
event_id TEXT,
user_id TEXT,
event_type TEXT,
amount DECIMAL,
item_id TEXT,
session_id TEXT,
event_time TIMESTAMPTZ
) FROM user_events_source;
Define lifetime aggregation features:
CREATE MATERIALIZED VIEW user_activity_features AS
SELECT
user_id,
COUNT(*) FILTER (WHERE event_type = 'purchase') AS purchases_total,
COUNT(*) FILTER (WHERE event_type = 'view') AS views_total,
SUM(amount) FILTER (WHERE event_type = 'purchase') AS total_spend,
MAX(event_time) AS last_active_at
FROM user_events
GROUP BY user_id;
This view maintains a running count of purchases, views, and total spend per user. Every purchase event updates only that user's row. No scheduled jobs. No batch windows. The feature value reflects the current state of the event stream.
Velocity features using tumbling windows
For features that need a time-scoped window -- activity in the last hour, spend in the last day -- use tumbling windows:
CREATE MATERIALIZED VIEW user_hourly_velocity AS
SELECT
user_id,
COUNT(*) AS events_this_hour,
SUM(CASE WHEN event_type = 'purchase' THEN amount ELSE 0 END) AS spend_this_hour,
window_start,
window_end
FROM TUMBLE(user_events, event_time, INTERVAL '1' HOUR)
GROUP BY user_id, window_start, window_end;
The TUMBLE function partitions the event stream into fixed hourly windows. RisingWave maintains results for each open window, closing and archiving old windows as time advances.
For overlapping windows that avoid cold edges, use hopping windows:
CREATE MATERIALIZED VIEW user_velocity_15min_hop AS
SELECT
user_id,
COUNT(*) AS events_15min,
SUM(CASE WHEN event_type = 'purchase' THEN amount ELSE 0 END) AS spend_15min,
window_start,
window_end
FROM HOP(user_events, event_time, INTERVAL '5' MINUTE, INTERVAL '15' MINUTE)
GROUP BY user_id, window_start, window_end;
Here the hop size is 5 minutes and the window size is 15 minutes. A new 15-minute window opens every 5 minutes. Events near window boundaries fall cleanly into at least one window.
Account risk features from PostgreSQL CDC
RisingWave's native CDC connector captures changes from a source PostgreSQL database without a Kafka intermediary:
CREATE SOURCE pg_cdc_source WITH (
connector = 'postgres-cdc',
hostname = 'pg-host',
port = '5432',
username = 'replication_user',
password = 'secret',
database.name = 'appdb',
schema.name = 'public',
publication.name = 'risingwave_pub'
);
Create streaming materialized views that join CDC data with event stream data:
CREATE MATERIALIZED VIEW account_risk_features AS
SELECT
a.user_id,
a.account_age_days,
a.verification_level,
COUNT(d.dispute_id) AS dispute_count_90d,
SUM(d.amount) AS disputed_amount_90d
FROM accounts a
LEFT JOIN disputes d ON d.user_id = a.user_id
AND d.created_at >= NOW() - INTERVAL '90 days'
GROUP BY a.user_id, a.account_age_days, a.verification_level;
When a new dispute row is inserted in the source PostgreSQL database, RisingWave captures it via CDC and updates the account_risk_features view incrementally. The latency from PostgreSQL write to materialized view update is typically under a second.
Feature Serving: Connecting Your Model or Agent
Because RisingWave speaks the PostgreSQL wire protocol on port 4566, any PostgreSQL client library can read feature values. No custom SDK required.
A Python model serving function:
import psycopg2
conn = psycopg2.connect(
host="localhost",
port=4566,
database="dev",
user="root",
password=""
)
def get_features(user_id: str) -> dict:
with conn.cursor() as cur:
cur.execute("""
SELECT
ua.purchases_total,
ua.total_spend,
ua.last_active_at,
ar.account_age_days,
ar.dispute_count_90d,
ar.verification_level
FROM user_activity_features ua
JOIN account_risk_features ar ON ar.user_id = ua.user_id
WHERE ua.user_id = %s
""", (user_id,))
row = cur.fetchone()
if row is None:
return {}
return {
"purchases_total": row[0],
"total_spend": float(row[1] or 0),
"last_active_at": row[2].isoformat() if row[2] else None,
"account_age_days": row[3],
"dispute_count": row[4],
"verification_level": row[5],
}
This query reads from pre-computed materialized view results. It returns in single-digit milliseconds because it is not scanning raw events -- it is reading a pre-maintained result row. The freshness of that row depends on how recently the underlying events arrived, not on a batch schedule.
For AI agents, the same function works. The agent queries features by entity ID, gets a structured dict back, and uses it in its decision context. Because the feature values reflect what happened seconds ago rather than hours ago, the agent's decisions are grounded in current reality.
Sinking Features to External Systems
If your existing serving infrastructure reads from Redis, a downstream Kafka consumer, or an Apache Iceberg table, RisingWave can push features there:
CREATE SINK user_activity_features_kafka
FROM user_activity_features
WITH (
connector = 'kafka',
topic = 'user-features',
properties.bootstrap.server = 'kafka:9092',
type = 'upsert',
primary_key = 'user_id'
) FORMAT UPSERT ENCODE JSON;
Every time a user's activity features change, RisingWave emits an updated record to the user-features Kafka topic. A downstream consumer can write this to Redis or any other online store. This pattern lets you layer RisingWave's streaming computation on top of an existing serving infrastructure rather than replacing it.
For training data, sink to Apache Iceberg to build a historical feature archive:
CREATE SINK user_activity_features_iceberg
FROM user_activity_features
WITH (
connector = 'iceberg',
type = 'upsert',
primary_key = 'user_id',
warehouse.path = 's3://feature-warehouse/features',
database.name = 'ml_features',
table.name = 'user_activity_features',
catalog.type = 'rest',
catalog.uri = 'http://iceberg-catalog:8181'
);
The Iceberg sink creates a time-stamped record every time features change. Your training pipeline reads from Iceberg with point-in-time filters to reconstruct what feature values looked like at any historical timestamp. This is how you generate training labels without training-serving skew: the training pipeline uses the same computation logic (same SQL view) that the serving layer uses.
Comparison: Feast vs Tecton vs RisingWave
| Dimension | Feast (open source) | Tecton (now Databricks) | RisingWave |
| Freshness | Minutes (batch) or seconds (streaming, more complex) | Seconds to minutes | Milliseconds to seconds |
| Offline store | Yes (BigQuery, Snowflake, Redshift) | Yes | Via Iceberg sink |
| Online store | Yes (Redis, DynamoDB) | Yes (DynamoDB, Redis) | Built-in (materialized views) |
| Feature definition | Python SDK | Python SDK | SQL |
| Training-serving consistency | Requires careful engineering | Better than Feast, still two code paths | Same SQL, same view |
| Open source | Yes (Apache 2.0) | No (commercial, now Databricks) | Yes (Apache 2.0) |
| Agent integration | Requires custom serving layer | Requires custom serving layer | Direct PostgreSQL protocol |
| Architecture complexity | Offline store + online store + sync pipeline | Offline store + online store + sync pipeline | Single system |
| Best for | Mature ML teams with existing Spark pipelines | Databricks shops needing enterprise feature governance | New projects, agent features, sub-second freshness |
The comparison is not that RisingWave is universally better. It is that RisingWave optimizes for different things than Feast and Tecton were designed for.
When to Still Use Feast or Tecton
There are situations where the traditional feature store tools remain the right choice.
You have a mature ML training pipeline that relies on the offline store. If your data science team has a well-established workflow built around Feast's offline feature retrieval -- point-in-time feature joins for training data generation, feature registry with lineage, cross-team feature sharing -- the cost of migrating outweighs the benefit of improved online freshness. Feast's streaming support has improved, and RisingWave can sink to Feast's online store rather than replacing it.
You need sophisticated time-travel for training data consistency. Generating training datasets with exactly the feature values that existed at label time is a core feature store capability. Feast and Tecton handle this robustly through point-in-time join logic built into their offline retrieval APIs. With RisingWave, you can achieve this by sinking to Iceberg and performing point-in-time filters in SQL, but it requires more manual engineering than the built-in feature store tooling.
Complex Python feature transformations already exist. If your feature computation logic involves custom Python functions, complex transformations not expressible in SQL, or multi-step ML preprocessing that runs in PySpark, migrating to SQL materialized views is a rewrite, not a configuration change. The existing Python investment may represent months of engineering work.
You are a Databricks shop and Tecton is now native to your platform. If your organization is standardized on Databricks and Tecton's acquisition gives you tighter integration with your existing data platform, that integration value may outweigh the architectural simplicity of a streaming SQL approach.
When RisingWave Is the Better Answer
Agent features with sub-second freshness requirements. If you are building AI agents that make decisions on live events -- transaction approval, dynamic pricing, real-time personalization -- and your features need to reflect what happened seconds ago, the batch computation path of traditional feature stores will not meet the requirement. Streaming SQL materialized views update within milliseconds of each source event.
New projects starting fresh in 2026. When there is no existing feature store investment to protect, the operational simplicity of one system over three (batch compute engine plus offline store plus online store) is a significant advantage. The SQL definition model also means the same engineers who write application queries can define and maintain features.
SQL teams without Python ML expertise. Feature store tools built around Python SDKs create a dependency on ML engineering for what is often fundamentally a data transformation problem. SQL materialized views are accessible to any engineer comfortable with SQL, broadening who can own and maintain the feature pipeline.
You want one system for streaming analytics and feature serving. RisingWave already handles real-time dashboards, alerting, and operational analytics. Using it for feature serving adds another workload to an existing system rather than adding a new one. The operational surface stays the same.
Monitoring Feature Freshness
Once a streaming feature store is in production, you need to verify that features are actually fresh. RisingWave provides system tables for this:
-- Check Kafka consumer lag on the user events source
SELECT * FROM rw_kafka_job_lag;
-- Check CDC progress on the PostgreSQL source
SELECT * FROM rw_cdc_progress;
-- Check running streaming jobs
SELECT id, name, created_at
FROM rw_streaming_jobs
ORDER BY created_at DESC;
Elevated consumer_lag means features are falling behind the event stream. This will manifest as stale feature values without any obvious serving error -- queries will still succeed, but they will return feature values from minutes ago rather than seconds ago. Monitor consumer_lag as a feature freshness SLO.
For end-to-end freshness validation, write a canary event to the source, record the timestamp, and measure how long until last_active_at in user_activity_features reflects the canary. This gives you an empirical measure of feature staleness under your production load.
The Feature Store Is Infrastructure Now
In 2023, a real-time feature store was a differentiator. In 2026, it is table stakes for any ML or AI agent system that operates on live data. The question has shifted from "do we need real-time features?" to "what is the simplest architecture that delivers them?"
The simplest architecture for new projects in 2026 is a streaming SQL database with incremental materialized views. You define features once in SQL, the engine maintains them continuously, and your serving layer reads over a standard PostgreSQL connection. No separate batch compute. No sync pipeline. No Redis cluster to manage. No training-serving skew to chase down.
That is the argument for RisingWave as a feature store: not that it replaces every feature store capability that Feast and Tecton offer, but that for the core use case -- compute features fresh, serve them fast -- it is the simpler system.
Try RisingWave Cloud free, no credit card required. Sign up here.
Join the RisingWave community on Slack to ask questions and connect with ML engineers building streaming feature pipelines.

