Backfill Feature Views
Backfill recomputes the materialized values of your Feature Views over time ranges that you choose. Use it after you correct or add historical source data, so that the offline and online materializations reflect the updated data.
Materialization computes recent feature values on each run and doesn't revisit values that it has already written. A change to the source data for a past time range doesn't reach the materialized values until you backfill that time range. Use backfill in scenarios such as the following:
- An upstream data quality issue affected a past time range, and you corrected the source rows.
- Source data for a past time range arrived after materialization had already processed it.
A backfill is a one-time job that runs alongside your scheduled materialization. It doesn't change the materialization schedule. See Materialize Feature Views.
Requirements
databricks-feature-engineering0.18.2 and above. For other requirements, see Requirements.- Each Feature View is a batch aggregation feature that uses a
DeltaTableSourceand aSlidingWindoworTumblingWindow. Lifetime windows aren't supported. - Each Feature View is materialized and has completed at least one materialization run. Backfill recomputes values that materialization has already written, so it can't materialize a Feature View for the first time.
- You start the backfill as the same user or service principal that materialized the Feature Views, from the workspace where they are materialized.
Permissions
Backfill runs as you, and it reads and writes the same tables as your materialization, so it uses the same privileges as your materialization. For full Unity Catalog privilege descriptions, see Unity Catalog privileges reference.
- You must have
MANAGEon each Feature View that you backfill. - To check a backfill, you need
READ FEATUREon every Feature View in the backfill. To cancel a backfill, you needMANAGEon every Feature View in the backfill.
Start a backfill
To start a backfill, call backfill_features with the Feature Views to backfill and one or more time ranges:
FeatureEngineeringClient.backfill_features(
*, # Arguments are keyword-only
features: List[Union[str, Feature]], # Feature Views to backfill, as Feature objects or full names
backfill_ranges: List[BackfillRange], # Time ranges of source data to reprocess
request_id: Optional[str] = None, # Idempotency token, a UUID
tags: Optional[Dict[str, str]] = None, # Custom tags for cost attribution
budget_policy_id: Optional[str] = None, # Serverless usage policy for cost attribution
wait: bool = False, # Wait for the backfill to finish
) -> BackfillStatus:
All Feature Views in one call must produce values at the same times. They must share the same interval between values (the slide_duration of a SlidingWindow or the window_duration of a TumblingWindow) and the same offset. Otherwise, the call fails with an error that groups the Feature Views by interval, so that you can start a separate backfill for each group.
Each BackfillRange has a start_time, which is inclusive, and an end_time, which is exclusive. Both are Python datetime values. A datetime without a time zone is read as UTC. Each start_time must be earlier than its end_time, and the ranges in one call can't overlap. For how backfill interprets each range, see How backfill applies time ranges.
The following example backfills one week of history for two Feature Views:
from datetime import datetime, timezone
from databricks.feature_engineering import FeatureEngineeringClient
from databricks.feature_engineering.entities import BackfillRange
fe = FeatureEngineeringClient()
backfill = fe.backfill_features(
features=[
"main.feature_store.amount_sum_sliding_7d_1d",
"main.feature_store.transaction_count_sliding_7d_1d",
],
backfill_ranges=[
BackfillRange(
start_time=datetime(2026, 3, 1, tzinfo=timezone.utc),
end_time=datetime(2026, 3, 8, tzinfo=timezone.utc),
)
],
)
print(backfill.operation_name) # operations/<operation-id>
Before the backfill starts, backfill_features checks the following. If a check fails, the call fails with an error that names the affected Feature Views.
- Each Feature View meets the requirements, including a completed materialization run.
- You materialized each Feature View.
- You have the required privileges.
The method returns a BackfillStatus that describes the backfill. Its operation_name identifies the backfill, in the format operations/<operation-id>. See Monitor or cancel a backfill.
To make the call safe to retry, pass a UUID as request_id. A retry with the same request_id returns the original backfill instead of starting a new one.
To attribute the cost of a backfill, pass tags, budget_policy_id, or both. They apply only to that backfill. See Attribute costs with tags and serverless usage policies.
How backfill applies time ranges
Each range selects the source data to reprocess: the source rows with timestamps at or after start_time and before end_time. Backfill applies each range as follows:
- Ranges are aligned to whole feature values. Backfill recomputes whole feature values, so it widens each range outward to the nearest times at which the feature produces a value. A
SlidingWindowfeature produces a value everyslide_duration, and aTumblingWindowfeature produces one everywindow_duration, shifted by the window'soffsetif you set one. For example, for a feature with a 1-hourslide_duration, a range from 1:30 AM to 2:30 AM becomes 1:00 AM to 3:00 AM. You don't need to align ranges yourself. Ranges that overlap after alignment are combined into one. - Values after the range can change. Backfill rewrites every feature value whose time window includes reprocessed data. A window can end after
end_time, so values up to onewindow_durationafterend_timecan change. For example, for a feature with a 7-daywindow_duration, values up to 7 days afterend_timecan change. - Backfill stops at the most recent materialized values. Backfill recomputes only history that materialization has already written. If a range extends past the most recent materialized values, backfill stops there and leaves the later time range to your scheduled materialization.
- Unset bounds extend to the available data. If you omit
start_time, the range starts at the earliest timestamp in the source data. If you omitend_time, the range extends to the most recent materialized values.
The backfill_ranges of a BackfillStatus are your ranges after alignment. Backfill doesn't narrow them to the most recent materialized values, so a reported range can extend past the values that the backfill recomputed. You don't need to backfill the later values, because your scheduled materialization computes them from the current source data.
Offline and online tables
Backfill updates the offline table of a Feature View and, if the Feature View is also materialized to an online store, its online table. For a Feature View with both, backfill recomputes the offline table and then republishes the online table from it. You can't backfill only one of them.
The online table holds the latest value for each entity. A backfill changes online values only when it changes the latest value of an entity.
Monitor or cancel a backfill
backfill_features returns without waiting for the backfill to finish. To wait, pass wait=True, or call wait_for_backfill with the returned status:
backfill = fe.wait_for_backfill(backfill=backfill)
wait_for_backfill returns the final BackfillStatus when the backfill succeeds. If the backfill fails or is canceled, it raises an OperationFailed error that describes the reason. To limit how long it waits, pass a timeout as a timedelta. If the backfill hasn't finished by then, wait_for_backfill raises a TimeoutError. Stopping the wait doesn't cancel the backfill.
To check a backfill without waiting, or from another notebook or job, call get_backfill with the operation name:
backfill = fe.get_backfill(operation_name="operations/<operation-id>")
print(backfill.state) # For example, BackfillState.RUNNING
A BackfillStatus has the following fields:
operation_name: The name that identifies the backfill.state: The state of the backfill, as aBackfillStatevalue.feature_full_names: The full names of the Feature Views in the backfill.backfill_ranges: The aligned time ranges, asBackfillRangevalues with UTC bounds.error: The reason the backfill failed. This field is set only whenstateisFAILED.
The backfill state is one of the following values:
State | Description |
|---|---|
| The backfill was accepted and has not started running. |
| The backfill is running. |
| The backfill finished and recomputed the feature values in its ranges. |
| The backfill stopped because of an error. See Recover from a failed backfill. |
| The backfill was canceled before it finished. |
If you don't have the operation name, find the most recent backfill of a materialized feature in the latest_backfill_operation field returned by list_materialized_features, and pass it to get_backfill.
To cancel a backfill, call cancel_backfill with its status:
fe.cancel_backfill(backfill=backfill)
Canceling a backfill requests that it stop. A backfill that is about to finish can still succeed, so check its final state with get_backfill. Canceling a backfill that has already finished has no effect. A canceled backfill can leave some feature values recomputed, as described in Recover from a failed backfill.
Concurrency
A backfill runs alongside your scheduled materialization. Backfills of different Feature Views can also run at the same time.
Only one backfill can run for a Feature View at a time. If you start a backfill for a Feature View that already has a backfill in progress, the request fails with an ALREADY_EXISTS error. Wait for the previous backfill to finish before starting the next one.
Recover from a failed backfill
A failed or canceled backfill can stop before it finishes. Each value that the backfill rewrote before it stopped is fully recomputed. Values that it didn't reach keep their earlier values, so some Feature Views or time ranges might not be updated.
To recover, start the same backfill again. If you passed a request_id, pass a new one, because a retry with the original request_id returns the failed backfill instead of starting a new one. Backfill is safe to repeat. If the source data hasn't changed, recomputing a range that already succeeded produces the same values.
Limitations
- Only batch aggregation features that use a
DeltaTableSourceand aSlidingWindoworTumblingWindowcan be backfilled. Streaming features,ColumnSelectionfeatures, features with aRollingWindoworSawtoothWindow, features with a lifetime window, and features with other sources, such asRequestSource, can't be backfilled. - Feature Views that produce values at different intervals or offsets can't share one backfill. Start a separate backfill for each group.
- Backfill updates the offline table of a Feature View and, if the Feature View is also materialized to an online store, its online table. You can't backfill only one of them.
- Backfill doesn't fill time ranges after the most recent materialized values. Your scheduled materialization fills them.