Unified ML Feature Store

One feature definition serving both real-time inference and historical training queries, so the two never drift apart.

  • Python
  • PostgreSQL
  • Redis
  • FastAPI
  • Docker
  • Terraform
  • Prometheus
  • Typer

The problem

Training/serving skew is the quiet failure mode of production machine learning. A feature gets defined once in a training notebook and again, separately, in the serving path. The two definitions agree until they don’t, and when they diverge the model degrades without anything alerting.

This is an open-source feature store built around a single rule: one Python feature definition feeds both paths. Real-time inference reads from Redis, historical training queries read from Postgres, and neither has its own copy of the logic.

Point-in-time correctness

The harder half of the problem is not serving, it is building training sets that are not contaminated. If you join a label from March against a feature table as it looks today, the model trains on information that did not exist when the label was created. It scores beautifully offline and fails in production.

Retrieval resolves each feature value as of its label’s timestamp using a SQL LATERAL join, which produces leakage-free training sets over 500K rows across four feature views in about twelve seconds.

The online store

The serving side is a Redis hash-per-entity layout with per-view TTLs and composite entity keys, which keeps batch lookups to a single round trip: 100 entities at 4 ms p99. An idempotent offline-to-online materialisation job keeps it fed, sustaining roughly 40K rows/s, and being idempotent means a failed run can simply be run again.

Operability

A feature store nobody can operate is a liability. It ships with a FastAPI serving layer instrumented for Prometheus, a Typer CLI covering apply / list / materialize / export against a Postgres-backed registry, Terraform modules for an RDS and ElastiCache deployment, and GitHub Actions CI running ruff, mypy, and 62 tests across Python 3.10 through 3.12.