Feature stores have become a load-bearing item on ML platform roadmaps — usually before anyone has articulated which problem the platform is actually trying to solve. The tooling (Feast, Tecton, Hopsworks, Vertex AI Feature Store, SageMaker Feature Store) is real, the engineering problems it addresses are real, and for a small subset of teams the value is unambiguous. For most mid-market data orgs, adopting one is a six-figure detour that produces dashboards rather than predictions.

Here’s the honest version of the decision.

What a feature store actually solves

Two problems, both narrow and both expensive to solve any other way once you actually have them.

Online/offline parity. Training a model uses batch-computed features from a warehouse. Serving that model in production needs the same features computed the same way at low latency. The hard part isn’t standing up two systems — it’s guaranteeing the logic matches. A feature defined as “30-day rolling sum of order_value” computed in dbt at 02:00 UTC against analytics.orders is not, by default, the same feature the inference service reads from Redis at 14:32:07 UTC. Schema drift, time-window edge cases, and late-arriving data each silently widen training-serving skew until your model’s offline AUC stops predicting its online lift. A feature store enforces a single feature definition and materializes it to both lanes from the same code path.

Point-in-time correctness. When you generate a training set, every feature value for a given entity-event pair has to reflect what was knowable at that timestamp — no leakage from the future. Joining a users.lifetime_value snapshot taken last night onto a churn label from six months ago is the most common silent killer of model quality. Feature stores implement point-in-time joins as a first-class operation: given a list of (entity_id, event_timestamp) pairs, return the feature values that were valid as of each timestamp. Doing this correctly in plain SQL is possible — and most teams who try it ship subtle bugs the first three times.

If you have neither problem, you don’t need a feature store. You need a pipeline.

The decision criteria

Skip the feature store unless at least three of the following are true:

  1. Real-time inference at scale. You serve predictions inline in a user-facing flow with sub-200ms latency budgets, not batch scoring written to a table once a day.
  2. More than one model in production sharing features. A single model can keep its features in its own pipeline without ceremony. The economics shift when feature reuse across models becomes the bottleneck — typically at three or more production models touching overlapping entity domains.
  3. Active retraining cadence. You generate new training sets weekly or more often, and point-in-time joins are part of every refresh. If you retrain twice a year on a manually curated dataset, you don’t need automated point-in-time machinery.
  4. A dedicated ML platform team. Feature stores are infrastructure with their own operational surface — schema migrations, materialization SLAs, online-store capacity planning, monitoring for staleness. Without two engineers who own this, the store becomes shelfware in eighteen months.
  5. Demonstrated training-serving skew you can measure. You’ve already shipped models, you’ve already seen offline-online metric divergence, and you’ve traced it to feature inconsistency. This is the criterion that matters most. If you can’t point to the specific bug a feature store would have prevented, you’re buying insurance against a problem you may never have.

Two or fewer? Don’t.

What works for the other 80%

For most mid-market teams the answer is a discipline, not a product:

  • A features schema in your warehouse, with one dbt model per feature group, columns named and typed deliberately, and tests for null rates, value ranges, and freshness. This is your offline store. It costs nothing extra.
  • A thin Python module — call it features.py — that defines each feature as a function taking an entity_id and a timestamp and returning a value. The dbt model and the runtime service both call into the same logic. Not as airtight as a feature store’s enforced single definition, but with code review and a handful of integration tests it closes 90% of the skew gap.
  • Point-in-time joins via ASOF joins in Snowflake, BigQuery, or DuckDB. Snowflake’s ASOF JOIN and BigQuery’s RANGE_BUCKET-based patterns handle the temporal correctness problem in pure SQL once you’ve internalized the pattern. Document it in a runbook, code-review every training-set generation script against the runbook, and you’re 95% of the way to correctness without operating new infrastructure.
  • Redis or DynamoDB as your online store, populated by a scheduled job that reads the same dbt models. Yes, this is “two pipelines that have to match” — that’s the entire problem a feature store automates away. For two or three models with low feature counts and weekly retraining, the manual discipline is cheaper than the platform.

Adopt the feature store the day the manual discipline starts failing in production — when you have measurable skew you can’t reason about, when feature reuse across teams becomes a coordination tax, when retraining cadence outruns your ability to hand-verify point-in-time correctness. Not before. The teams that adopt early end up with a beautifully-instrumented system serving four features to one model, and a roadmap item to “drive feature store adoption” that never closes.

Most data orgs don’t have a feature store problem. They have a feature discipline problem, and the discipline is cheaper than the platform.