# \[Alpha] Feature View Versioning

Feature view versioning automatically tracks schema and UDF changes to feature views. Every time `feast apply` detects a change, a versioned snapshot is saved to the registry. This enables:

* **Audit trail** — see what a feature view looked like at any point in time
* **Safe rollback** — pin serving to a prior version with `version="v0"` in your definition
* **Multi-version serving** — serve both old and new schemas simultaneously using `@v<N>` syntax
* **Staged publishing** — use `feast apply --no-promote` to publish a new version without making it the default

## How It Works

Version tracking is fully automatic. You don't need to set any version parameter — just use `feast apply` as usual:

1. **First apply** — Your feature view definition is saved as **v0**.
2. **Change something and re-apply** — Feast detects the change, saves the old definition as a snapshot, and saves the new one as **v1**. The version number auto-increments on each real change.
3. **Re-apply without changes** — Nothing happens. Feast compares the new definition against the active one and skips creating a version if they're identical (idempotent).
4. **Another change** — Creates **v2**, and so on.

```
feast apply                  # First apply → v0
# ... edit schema ...
feast apply                  # Detects change → v1
feast apply                  # No change detected → still v1 (no new version)
# ... edit source ...
feast apply                  # Detects change → v2
```

**Key details:**

* **Automatic snapshots**: Versions are created only when Feast detects an actual change to the feature view definition (schema or UDF). Metadata-only changes (description, tags, TTL) update in place without creating a new version.
* **Separate history storage**: Version history is stored separately from the active feature view definition, keeping the main registry lightweight.
* **Backward compatible**: The `version` parameter is fully optional. Omitting it (or setting `version="latest"`) preserves existing behavior — you get automatic versioning with zero changes to your code.

## ConfigurationVersion history tracking is **always active** — no configuration needed. Every `feast apply` that changes a feature view automatically records a version snapshot.

To enable **versioned online reads** (e.g., `fv@v2:feature`), add `enable_online_feature_view_versioning: true` to your registry config in `feature_store.yaml`:

```yaml
registry:
  path: data/registry.db
  enable_online_feature_view_versioning: true
```

When this flag is off, version-qualified refs (e.g., `fv@v2:feature`) in online reads will raise errors, but version history, version listing, version pinning, and version lookups all work normally.## Pinning to a Specific Version

You can pin a feature view to a specific historical version by setting the `version` parameter. When pinned, `feast apply` replaces the active feature view with the snapshot from that version. This is useful for reverting to a known-good definition.

```python
from feast import FeatureView

# Default behavior: always use the latest version (auto-increments on changes)
driver_stats = FeatureView(
    name="driver_stats",
    entities=[driver],
    schema=[...],
    source=my_source,
)

# Pin to a specific version (reverts the active definition to v2's snapshot)
driver_stats = FeatureView(
    name="driver_stats",
    entities=[driver],
    schema=[...],
    source=my_source,
    version="v2",  # also accepts "version2"
)
```

When pinning, the feature view definition (schema, source, transformations, etc.) must match the currently active definition. If you've also modified the definition alongside the pin, `feast apply` will raise a `FeatureViewPinConflict` error. To apply changes, use `version="latest"`. To revert, only change the `version` parameter.

The snapshot's content replaces the active feature view. Version history is not modified by a pin; the existing v0, v1, v2, etc. snapshots remain intact.

After reverting with a pin, you can go back to normal auto-incrementing behavior by removing the `version` parameter (or setting it to `"latest"`) and running `feast apply` again. If the restored definition differs from the pinned snapshot, a new version will be created.

### Version string formats

| Format                          | Meaning                                                    |
| ------------------------------- | ---------------------------------------------------------- |
| `"latest"` (or omitted)         | Always use the latest version (auto-increments on changes) |
| `"v0"`, `"v1"`, `"v2"`, ...     | Pin to a specific version number                           |
| `"version0"`, `"version1"`, ... | Equivalent long form (case-insensitive)                    |

## Staged Publishing (`--no-promote`)

By default, `feast apply` atomically saves a version snapshot **and** promotes it to the active definition. For breaking schema changes, you may want to stage the new version without disrupting unversioned consumers.

The `--no-promote` flag saves the version snapshot without updating the active feature view definition. The new version is accessible only via explicit `@v<N>` reads and `--version` materialization.

**CLI usage:**

```bash
feast apply --no-promote
```

**Python SDK equivalent:**

```python
store.apply([entity, feature_view], no_promote=True)
```

### Phased rollout workflow

1. **Stage the new version:**

   ```bash
   feast apply --no-promote
   ```

   This publishes v2 without promoting it. All unversioned consumers continue using v1.
2. **Populate the v2 online table:**

   ```bash
   feast materialize --views driver_stats --version v2 ...
   ```
3. **Migrate consumers one at a time:**
   * Consumer A switches to `driver_stats@v2:trips_today`
   * Consumer B switches to `driver_stats@v2:avg_rating`
4. **Promote v2 as the default:**

   ```bash
   feast apply
   ```

   Or pin to v2: set `version="v2"` in the definition and run `feast apply`.

## Listing Version History

Use the CLI to inspect version history:

```bash
feast feature-views list-versions driver_stats
```

```
VERSION  TYPE          CREATED              VERSION_ID
v0       feature_view  2024-01-15 10:30:00  a1b2c3d4-...
v1       feature_view  2024-01-16 14:22:00  e5f6g7h8-...
v2       feature_view  2024-01-20 09:15:00  i9j0k1l2-...
```

Or programmatically via the Python SDK:

```python
store = FeatureStore(repo_path=".")
versions = store.list_feature_view_versions("driver_stats")
for v in versions:
    print(f"{v['version']} created at {v['created_timestamp']}")
```

## Version-Qualified Feature References

You can read features from a **specific version** of a feature view by using version-qualified feature references with the `@v<N>` syntax:

```python
online_features = store.get_online_features(
    features=[
        "driver_stats:trips_today",           # latest version (default)
        "driver_stats@v2:trips_today",        # specific version
        "driver_stats@latest:trips_today",    # explicit latest
    ],
    entity_rows=[{"driver_id": 1001}],
)
```

**How it works:**

* `driver_stats:trips_today` is equivalent to `driver_stats@latest:trips_today` — it reads from the currently active version
* `driver_stats@v2:trips_today` reads from the v2 snapshot stored in version history, using a version-specific online store table
* Multiple versions of the same feature view can be queried in a single request (e.g., `driver_stats@v1:trips` and `driver_stats@v2:trips_daily`)

**Backward compatibility:**

* The unversioned online store table (e.g., `project_driver_stats`) is treated as v0
* Only versions >= 1 get `_v{N}` suffixed tables (e.g., `project_driver_stats_v1`)
* Pre-versioning users' existing data continues to work without changes — `@latest` resolves to the active version, which for existing unversioned FVs is v0

**Materialization:** Each version requires its own materialization. After applying a new version, run `feast materialize` to populate the versioned table before querying it with `@v<N>`.

## Supported Feature View Types

Versioning is supported on all three feature view types:

* `FeatureView` (and `BatchFeatureView`)
* `StreamFeatureView`
* `OnDemandFeatureView`

## Online Store Support**Currently, version-qualified online reads (`@v<N>`) are only supported with the SQLite online store.** Support for additional online stores (Redis, DynamoDB, Bigtable, Postgres, etc.) will be added based on community priority.

If you need versioned online reads for a specific online store, please [open a GitHub issue](https://github.com/feast-dev/feast/issues/new) describing your use case and which store you need. This helps us prioritize development.

Version history tracking in the registry (listing versions, pinning, `--no-promote`) works with **all** registry backends (file, SQL, Snowflake).

## Full Details

For the complete design, concurrency semantics, and feature service interactions, see the [Feature View Versioning RFC](https://github.com/feast-dev/feast/blob/master/docs/rfcs/feature-view-versioning.md).

## Naming Restrictions

Feature references use a structured format: `feature_view_name@v<N>:feature_name`. To avoid ambiguity, the following characters are reserved and must not appear in feature view or feature names:

* **`@`** — Reserved as the version delimiter (e.g., `driver_stats@v2:trips_today`). `feast apply` will reject feature views with `@` in their name. If you have existing feature views with `@` in their names, they will continue to work for unversioned reads, but we recommend renaming them to avoid ambiguity with the `@v<N>` syntax.
* **`:`** — Reserved as the separator between feature view name and feature name in fully qualified feature references (e.g., `driver_stats:trips_today`).

## Known Limitations

* **Online store coverage** — Version-qualified reads (`@v<N>`) are SQLite-only today. Other online stores are follow-up work.
* **Offline store versioning** — Versioned historical retrieval is not yet supported.
* **Version deletion** — There is no mechanism to prune old versions from the registry.
* **Cross-version joins** — Joining features from different versions of the same feature view in `get_historical_features` is not supported.
* **Feature services** — Feature services always resolve to the active (promoted) version. `--no-promote` versions are not served until promoted.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.feast.dev/master/reference/alpha-feature-view-versioning.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
