Lightweight feature store for small and medium teams
Project description
feature-forge
Lightweight feature store for small and medium ML teams. Define features in YAML, get point-in-time correct data with one method call. No infrastructure required.
Install
pip install feature-forge
With optional backends:
pip install feature-forge[databricks] # Databricks Unity Catalog
pip install feature-forge[spark] # PySpark engine
pip install feature-forge[all] # Everything
What it does
- Point-in-time correct joins: for each row in your data, features are computed using only past information. No data leakage.
- YAML-based feature definitions: entities, sources, and features are declared in version-controlled YAML files.
- Multiple data sources: Parquet (local), S3/GCS/Azure, SQLite/PostgreSQL, Databricks Unity Catalog.
- Two query engines: DuckDB (default, zero-config) or PySpark (for Spark clusters).
- One method for everything:
get_features_table()handles training, inference, and historical backfill. - CLI included: init, validate, list, describe, materialize.
Quickstart
1. Initialize
feature-forge init my_features/
2. Define (edit the generated YAML files)
# entities.yml
entities:
- name: customer
join_keys: [customer_id]
# sources.yml
sources:
- name: transactions
backend: parquet
path: data/transactions.parquet
entity: customer
timestamp_column: event_timestamp
columns:
- { name: customer_id, dtype: int64 }
- { name: amount, dtype: float64 }
- { name: event_timestamp, dtype: timestamp }
# features.yml
feature_views:
- name: customer_features
entity: customer
source: transactions
features:
- name: txn_count_7d
dtype: int64
aggregation: { function: count, column: amount, window: 7d }
- name: avg_amount_30d
dtype: float64
aggregation: { function: avg, column: amount, window: 30d }
3. Validate
feature-forge validate --repo my_features/
4. Use
from feature_forge import FeatureStore
import pandas as pd
store = FeatureStore("my_features/")
labels = pd.DataFrame({
"customer_id": [101, 102],
"event_timestamp": pd.to_datetime(["2025-03-15", "2025-03-20"]),
"is_fraud": [1, 0],
})
df = store.get_features_table(
entity_df=labels,
feature_views=["customer_features"],
)
# customer_id | event_timestamp | is_fraud | txn_count_7d | avg_amount_30d
# Each row uses ONLY data before its timestamp
Example: training, inference, and backfill
from feature_forge import FeatureStore
store = FeatureStore("my_features/")
# TRAINING: pass labeled data with historical timestamps
training_df = store.get_features_table(
entity_df=labels_df,
feature_views=["customer_features"],
)
# INFERENCE: pass entity IDs, features computed as of now
inference_df = store.get_features_table(
entity_ids={"customer_id": [101, 102, 103]},
feature_views=["customer_features"],
)
# BACKFILL: entity IDs + date range for historical scoring
backfill_df = store.get_features_table(
entity_ids={"customer_id": [101, 102]},
feature_views=["customer_features"],
start_date="2025-01-01",
end_date="2025-06-01",
interval="1d",
)
store.close()
Same method, same PIT guarantees. The behavior changes based on which parameters you pass.
Documentation
| Guide | Description |
|---|---|
| Getting Started | 5-minute setup |
| Defining Features | Entities, sources, aggregation vs passthrough |
| Retrieving Features | Training, inference, backfill modes |
| Backends | Parquet, S3, SQL, Databricks configuration |
| Engines | DuckDB vs PySpark |
| Materialization | Pre-compute and save to Parquet |
| CLI Reference | All commands and flags |
Development
git clone https://github.com/pydoni/feature-forge.git
cd feature-forge
uv sync --extra dev
uv run pytest
License
Apache 2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fforge-1.0.0.tar.gz.
File metadata
- Download URL: fforge-1.0.0.tar.gz
- Upload date:
- Size: 47.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea9718a9102d5f5980fff3375419d76fc8d9f38149be312f9548724860a4af6b
|
|
| MD5 |
e0ac2f738a8c3c936c17c7269611a3e4
|
|
| BLAKE2b-256 |
4c2c45c22a8150e134a35577534d542256960ad09700f4e81b327c0b1528bef6
|
File details
Details for the file fforge-1.0.0-py3-none-any.whl.
File metadata
- Download URL: fforge-1.0.0-py3-none-any.whl
- Upload date:
- Size: 36.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ffc97b2aca0609d89bbff3a427f4db848cc7f1a1211d9c49a7037b3124fc278
|
|
| MD5 |
b677aebe57ae3ecf28fc1a2771588506
|
|
| BLAKE2b-256 |
490430dd55c6d12af70fd3e67a3a936832f540a0f925270380fdb247aaf6a429
|