How to Configure a Custom Offline Store in Feast
To configure a custom offline store in Feast, implement a configuration class inheriting from FeastConfigBaseModel and a store class inheriting from OfflineStore, then reference the fully-qualified store class name in the offline_store.type field of your feature_store.yaml.
Feast supports pluggable offline storage backends, enabling integration with proprietary databases, cloud object stores, or bespoke file formats beyond the built-in options. According to the feast-dev/feast source code, the framework dynamically instantiates custom implementations declared in feature_store.yaml through the RepoConfig parser in sdk/python/feast/repo_config.py. This guide details the exact implementation pattern required to build, register, and test a production-ready custom offline store.
Architecture Overview
Feast discovers and loads offline stores through a dynamic factory pattern defined in sdk/python/feast/repo_config.py. When parsing feature_store.yaml, the RepoConfig.offline_store property inspects the type field and invokes get_offline_config_from_type() to instantiate your configuration class. Your configuration class then points to the concrete OfflineStore implementation via its type attribute. The store class must implement the abstract interface defined in sdk/python/feast/infra/offline_stores/offline_store.py, specifically returning RetrievalJob objects from its query methods.
Implementation Requirements
Creating a custom offline store requires exactly two Python classes:
- Configuration Class: Inherits from
FeastConfigBaseModeland contains atypefield (as aLiteral) that exactly matches the fully-qualified name of your store class. - Store Class: Inherits from
OfflineStoreand implements the required retrieval methods that returnRetrievalJobinstances.
Step 1: Create the Configuration Class
Define a Pydantic-based configuration class that specifies your store's connection parameters. The critical requirement is the type field, which must be a Literal string containing the fully-qualified class name of your offline store implementation.
# src/feast_custom_offline_store/file.py
from typing import Literal
from feast.repo_config import FeastConfigBaseModel
class CustomFileOfflineStoreConfig(FeastConfigBaseModel):
"""Configuration for a file-based custom offline store."""
type: Literal["feast_custom_offline_store.file.CustomFileOfflineStore"] = \
"feast_custom_offline_store.file.CustomFileOfflineStore"
uri: str # Path or URI to the data source (e.g., s3://bucket/prefix/)
As implemented in sdk/python/feast/repo_config.py, Feast uses this type value to resolve and instantiate the corresponding store class at runtime.
Step 2: Implement the Offline Store Class
Your store class must inherit from OfflineStore and implement at least two abstract methods: get_historical_features() and pull_latest_from_table_or_query(). These methods return RetrievalJob objects that encapsulate the query execution logic.
# src/feast_custom_offline_store/file.py
from typing import List, Optional
from datetime import datetime
import warnings
from feast.infra.offline_stores.offline_store import OfflineStore, RetrievalJob
from feast.repo_config import RepoConfig
from feast.data_source import DataSource
class CustomFileOfflineStore(OfflineStore):
"""Custom file-based offline store implementation."""
def get_historical_features(
self,
config: RepoConfig,
feature_views: List,
feature_refs: List[str],
entity_df,
registry,
project: str,
full_feature_names: bool = False,
) -> RetrievalJob:
warnings.warn("Custom offline store is experimental; API may change.", RuntimeWarning)
# Implementation: read historical features based on entity_df
# Must return a concrete RetrievalJob subclass
pass
def pull_latest_from_table_or_query(
self,
config: RepoConfig,
data_source: DataSource,
join_key_columns: List[str],
feature_name_columns: List[str],
timestamp_field: str,
created_timestamp_column: Optional[str],
start_date: datetime,
end_date: datetime,
) -> RetrievalJob:
warnings.warn("Custom offline store is experimental; API may change.", RuntimeWarning)
# Implementation: query data_source for features between start_date and end_date
pass
Optional methods include pull_all_from_table_or_query(), offline_write_batch(), and write_logged_features(), which enable additional Feast functionality like batch materialization and feature logging.
Step 3: Configure feature_store.yaml
Add your custom store to the feature_store.yaml configuration file. The offline_store.type value must exactly match the fully-qualified class name defined in your configuration class's type Literal.
project: my_project
registry: data/registry.db
provider: local
offline_store:
type: feast_custom_offline_store.file.CustomFileOfflineStore
uri: "s3://my-bucket/feature-data/"
online_store:
path: data/online_store.db
When FeatureStore(repo_path=".") initializes, RepoConfig in sdk/python/feast/repo_config.py parses this YAML and instantiates your CustomFileOfflineStore via the get_offline_config_from_type factory.
Step 4: Optional Plugin Registration
For broader distribution within the Feast ecosystem, place your implementation under sdk/python/feast/infra/offline_stores/contrib/<your_plugin>/. Update setup.cfg or pyproject.toml to register the package as a Feast extra. This makes your store discoverable without requiring users to modify PYTHONPATH or install separate packages manually.
Testing Your Custom Implementation
Validate your implementation against Feast's offline store test suite located in sdk/python/tests/unit/infra/offline_stores/test_offline_store.py. Add your store's class name to the offline_store_type parametrization to ensure compatibility with core Feast operations like materialization and historical feature retrieval.
from feast import FeatureStore
# Load the configuration
store = FeatureStore(repo_path="feature_repo")
# Test materialization (calls pull_latest_from_table_or_query)
store.materialize(incremental=True)
# Test historical retrieval (calls get_historical_features)
historical_job = store.get_historical_features(
entity_df=entity_dataframe,
feature_refs=["driver:rating"],
)
df = historical_job.to_df()
Summary
- Two-class requirement: Implement both a
FeastConfigBaseModelsubclass for configuration and anOfflineStoresubclass for logic. - Type field alignment: The
typeLiteral in your config class must exactly match the fully-qualified name of your store class. - Abstract methods: You must implement
get_historical_features()andpull_latest_from_table_or_query()returningRetrievalJobobjects. - YAML configuration: Reference the fully-qualified store class name in
feature_store.yamlunderoffline_store.type. - Source files: Reference
sdk/python/feast/repo_config.pyfor configuration parsing andsdk/python/feast/infra/offline_stores/offline_store.pyfor the abstract interface.
Frequently Asked Questions
What are the required methods for a custom offline store in Feast?
You must implement get_historical_features() and pull_latest_from_table_or_query() in your OfflineStore subclass. Both methods must return a RetrievalJob object as defined in sdk/python/feast/infra/offline_stores/offline_store.py. Optional methods include pull_all_from_table_or_query(), offline_write_batch(), and write_logged_features().
How does Feast locate my custom offline store class?
Feast uses the type field in your feature_store.yaml to dynamically import your class. In sdk/python/feast/repo_config.py, the get_offline_config_from_type() function resolves the string value of offline_store.type to your configuration class, which then points to the concrete OfflineStore implementation via its own type attribute.
Can I use environment variables in my custom offline store configuration?
Yes. Since your configuration class inherits from FeastConfigBaseModel (a Pydantic base model), you can use Pydantic's Field with env parameters or standard Python initialization to read environment variables. The configuration instance is created during RepoConfig initialization, making runtime environment values available to your store implementation.
Where should I place unit tests for my custom offline store?
Add tests to sdk/python/tests/unit/infra/offline_stores/test_offline_store.py or create a new test file that imports the generic offline store test suite. Parametrize your store class name in the offline_store_type fixture to ensure your implementation passes Feast's standardized materialization and historical retrieval tests.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →