# How to Configure a Custom Offline Store in Feast

> Learn how to configure a custom offline store in Feast by implementing configuration and store classes. Point to your custom store in feature_store.yaml for tailored data storage.

- Repository: [Feast/feast](https://github.com/feast-dev/feast)
- Tags: how-to-guide
- Published: 2026-03-01

---

**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`](https://github.com/feast-dev/feast/blob/main/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`](https://github.com/feast-dev/feast/blob/main/feature_store.yaml) through the `RepoConfig` parser in [`sdk/python/feast/repo_config.py`](https://github.com/feast-dev/feast/blob/main/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`](https://github.com/feast-dev/feast/blob/main/sdk/python/feast/repo_config.py). When parsing [`feature_store.yaml`](https://github.com/feast-dev/feast/blob/main/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`](https://github.com/feast-dev/feast/blob/main/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 `FeastConfigBaseModel` and contains a `type` field (as a `Literal`) that exactly matches the fully-qualified name of your store class.
- **Store Class**: Inherits from `OfflineStore` and implements the required retrieval methods that return `RetrievalJob` instances.

## 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.

```python

# 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`](https://github.com/feast-dev/feast/blob/main/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.

```python

# 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`](https://github.com/feast-dev/feast/blob/main/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.

```yaml
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`](https://github.com/feast-dev/feast/blob/main/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`](https://github.com/feast-dev/feast/blob/main/setup.cfg) or [`pyproject.toml`](https://github.com/feast-dev/feast/blob/main/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`](https://github.com/feast-dev/feast/blob/main/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.

```python
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 `FeastConfigBaseModel` subclass for configuration and an `OfflineStore` subclass for logic.
- **Type field alignment**: The `type` Literal in your config class must exactly match the fully-qualified name of your store class.
- **Abstract methods**: You must implement `get_historical_features()` and `pull_latest_from_table_or_query()` returning `RetrievalJob` objects.
- **YAML configuration**: Reference the fully-qualified store class name in [`feature_store.yaml`](https://github.com/feast-dev/feast/blob/main/feature_store.yaml) under `offline_store.type`.
- **Source files**: Reference [`sdk/python/feast/repo_config.py`](https://github.com/feast-dev/feast/blob/main/sdk/python/feast/repo_config.py) for configuration parsing and [`sdk/python/feast/infra/offline_stores/offline_store.py`](https://github.com/feast-dev/feast/blob/main/sdk/python/feast/infra/offline_stores/offline_store.py) for 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`](https://github.com/feast-dev/feast/blob/main/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`](https://github.com/feast-dev/feast/blob/main/feature_store.yaml) to dynamically import your class. In [`sdk/python/feast/repo_config.py`](https://github.com/feast-dev/feast/blob/main/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`](https://github.com/feast-dev/feast/blob/main/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.