Today's ML stack handles cheap large-scale storage and efficient model training well. Its least improved layer remains the path from raw data to model-ready features, especially the part that must update continuously as new data arrives.
Most teams still calculate features in batch. A scheduled job scans a table, applies transformations, and writes the results to a feature store on a fixed interval. Features become stale between runs. This limitation is built into the batch model and constrains real-time model performance, regardless of the training pipeline's sophistication.
Incremental computation, defined precisely
Incremental computation means updating an output after an input change with work proportional to that change, O(delta), rather than to the full input, O(total_rows). In a SQL GROUP BY aggregation, one new row requires recomputing only the affected group's aggregate. Every other group remains unchanged.
The optimization is intuitive, but supporting arbitrary SQL correctly requires substantial engine infrastructure. The engine must retain enough state to derive delta output from each delta input, process retract events, including deletes and updates, propagate changes through multi-stage query plans, and keep multiple materialized views consistent when they share intermediate state.
Feldera compiles SQL queries into an operator graph composed of incremental operators. As each new row enters, it moves through the graph as a delta. Only operators whose state changes perform work. Consequently, a pipeline with dozens of features processes an event according to the number of affected features, not the full history or total feature count.
Why batch recomputation costs compound
At modest scale, the gap between incremental and batch computation can seem unimportant. A GROUP BY over 10 million rows may finish in seconds, and hourly execution may be affordable. Scaling introduces two compounding costs.
First, the data grows. Running a GROUP BY over 1 billion rows that takes 10 minutes, hourly, is expensive. Replacing it with a per-event delta operation that takes milliseconds can save orders of magnitude in daily compute. Second, features become more complex. A basic GROUP BY may evolve into a multi-stage aggregation joining several tables, with every batch stage adding latency. Incrementally, each stage is an independently maintained materialized view, so end-to-end latency becomes the sum of a few fast delta operations.
-- Batch job cost model: O(total_rows) per run
-- Week 1: 7 * 24 runs * 10M rows = 1.68B rows scanned
-- Week 4: 28 * 24 runs * 70M rows = ~47.0B rows scanned
-- Cost grows as dataset accumulates, not just as events arrive
-- Incremental model: O(new_rows) per tick
-- Week 1: 100K new rows/hour = 2.4M rows processed
-- Week 4: 100K new rows/hour = 2.4M rows processed
-- Cost is constant in the arrival rate, zero accumulation
CREATE MATERIALIZED VIEW user_features AS
SELECT
user_id,
COUNT(*) AS events_30d,
SUM(value) AS total_value_30d,
AVG(value) AS avg_value_30d
FROM events
WHERE ts >= NOW() - INTERVAL '30 days'
GROUP BY user_id;
-- Feldera maintains this with O(delta) work per new row
How incremental computation fits the existing stack
Incremental computation is not a replacement for every batch use case. Batch remains suitable for backfill computations, one-time historical analyses, and infrequently calculated features based on large static datasets. Its strongest fit is the online feature layer, where features are read during model serving and must reflect the world's state as recently as possible.
For most teams, the practical architecture is hybrid: batch pipelines provide historical training data and backfill, while incremental pipelines support the online feature store for live predictions. The incremental layer handles steady-state streaming. Batch covers historical reprocessing, such as recomputing past values after a feature definition changes so the model can be retrained.
This division also reduces online-offline skew. Using the same SQL view definition for the incremental serving pipeline and batch backfill gives both pipelines identical aggregation semantics. Serving features cannot silently use different windowing logic from training features, a common cause of unexplained production model degradation.
The ML freshness curve
Fresher features do not benefit every model equally. Each use case has its own relationship between feature freshness and model quality. Identifying that curve helps determine whether incremental pipelines deserve priority.
For fraud detection models based on velocity features, the curve is steep and short. Feature age beyond a few minutes sharply reduces performance because fraud patterns operate on minute-level timescales. Recommendation systems using session-level behavioral signals have a steep but somewhat longer curve: freshness during the current session, from minutes to an hour, matters, while staleness beyond the session boundary has diminishing marginal impact. For churn prediction models using 30-day behavioral summaries, the curve is nearly flat. Hourly updates perform almost the same as real-time updates because the signal is long-horizon.
Incremental pipelines should therefore focus on features with steep freshness curves. If 80% of predictive power comes from long-horizon aggregations and 20% from velocity features, incremental pipelines still help, but most of the value lies in that 20%. A pragmatic strategy is to incrementally compute high-stakes, time-sensitive features while leaving long-horizon features in batch, rather than converting the whole feature library at once.
Starting without replacing the stack
Begin by finding features most sensitive to latency, where staleness directly harms live model performance. For many fraud and recommendation teams, this is a small group of behavioral aggregations: velocity features, session features, and recency scores. They are high-value targets for an incremental pipeline and are often simple enough SQL to incrementalize without rewriting the feature library.
Feldera connects to existing Kafka topics and writes to the feature store endpoints already used by batch pipelines. Adding an incremental layer for time-sensitive features does not require changes to model serving or the training data pipeline. The migration is additive: run incremental and batch pipelines together, verify matching historical output, then switch serving to the incrementally maintained features. Batch remains available for training-data backfill and periods when the incremental pipeline restarts.