This walkthrough is an authored example of a decision, not a tested migration.
Step 1: Decide whether the change is compatible
Adding an optional field can stay on the same version if old readers ignore it. Removing a field, or changing what a field means, needs a new version.
Checkpoint
You can say whether readers of the current version will still understand the event.
Step 2: Read both versions at the boundary
Accept the versions you still support, and translate them into the shape your system stores. Do not make every downstream worker learn both shapes.
export function normalize(event: { version: number; total?: number; amount?: number }) {
if (event.version === 1) return { amount: event.total ?? 0 };
return { amount: event.amount ?? 0 };
}Checkpoint
A version 1 event and a version 2 event both become the stored shape, and an unknown version is rejected.