---
title: Change tracking
description: Detect added and changed components and resources.
sidebar:
  order: 7
---

`[TrackChanges]` enables added and changed stamps for a component or resource. A change filter on an untracked type is an error ([`AV006`](/docs/reference/diagnostics)).

## What a system observes

A system observes stamps satisfying `lastSuccessfulRun < stamp <= thisRun`. A skipped or failed body does not advance its last successful tick. Conditions have separate ticks and cursors.

## What stamps a change

| Operation | Added | Changed |
| --- | --- | --- |
| Insertion | Stamped | Stamped |
| Replacement | Preserved | Stamped, including equal-value replacement |
| Moving between archetypes | Preserved | Preserved for surviving components |
| Readonly access | Unchanged | Unchanged |

A generated writable row property stamps before returning its ref. `[Each]` stamps tracked writable refs before the method call. `[EachBlock]` stamps every row of a tracked writable span before the method call. `ResMut<T>.Value` follows the same rule.

## Skipping unchanged archetypes

Each archetype keeps the newest added and changed stamp of every tracked component. An `Added<T>` or `Changed<T>` filter skips an archetype whose newest stamp predates the system's last successful run, without reading its rows. A scan in a world where little changed therefore costs time in proportion to the archetypes that did change, not to every entity.

Removing or moving an entity does not lower an archetype's newest stamp. The filter then reads that archetype's rows and finds no match, so the result is still exact. `[EachBlock]` is the exception: it applies the filter [per block](/docs/guides/systems#eachblock), not per row.

:::note
Taking a writable ref counts as a change even when the method leaves the value unchanged. Use `Read<T>` or `scoped in` when you do not intend to write.
:::
