Terraform Guide

How to document an infrastructure migration: before, target, and current

By the engineer who builds Datadef, from client work on data platforms · Reviewed August 21, 2026

Every migration produces the same argument around month four. Someone opens a diagram, someone else says that is the old one, and a third person says no, that is the target. All three are looking at pictures that were true at some point. Naming the three artifacts up front, and generating exactly one of them, ends the argument permanently.

7 min readFor teams mid-migration whose diagrams have started contradicting each other

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

149/20003 credits left
Try:

No account needed · Editable canvas, not a picture

Three artifacts with three different lifetimes

The before is a snapshot. It is frozen on purpose, dated, and never edited again, because its whole job is to be the thing you compare against and the evidence in the decision record.

The target is a proposal. It is hand-drawn or hand-edited, it changes when the plan changes, and it is explicitly not derived from the code, since the code does not describe it yet. Every change to it should be a decision someone made, not a merge.

The current is generated. It follows the repository automatically and nobody edits it, because the moment someone does, it stops being an honest answer to what does the system look like today.

Label them in the title, not in a caption people will crop out. Before (2026-02-14, tag v3.2), Target (revision 4), Current (synced from main). Three lifetimes, three labels, zero arguments.

Freezing a before that is still reproducible

Screenshots decay because nobody can tell where they came from. Anchor the before to a commit: connect the repository at the tag or branch that represents the pre-migration state, and the diagram is regenerable from that exact point rather than being a picture nobody can reproduce. Note the tag under the image and the artifact becomes evidence rather than decoration.

For the decision record itself, export the frozen version as PNG or JPEG and attach it. Duplicate the project if you also want to annotate the before with arrows and commentary, because a synced project regenerates from the code and would overwrite hand annotations on the next refresh. The canvas is where that annotated copy lives.

## Migration: on-prem warehouse to lakehouse

**Before** synced from tag `pre-migration-v3.2`, frozen 2026-02-14
**Target** revision 4, approved 2026-03-02, owner: platform team
**Current** live embed, synced daily from `main`

### Done when
- no node in Current sits in the legacy zone
- the legacy stack directory no longer exists in the repo

Let the current diagram decide when you are finished

A migration in progress has a recognizable shape in a generated diagram: the old components and the new ones both present, with crossing paths between them. That is not a drawing problem, it is the actual state of the system, and a strangler migration is supposed to look like that for months.

It also gives you a completion test that nobody can argue with. The migration is done when the legacy nodes stop appearing in the generated diagram, because they stopped being declared in the repository. Written into the decision record as a done-when clause, that turns a subjective milestone into a check anyone can run.

Between those two points the current diagram maintains itself. The daily sync re-reads the branch, node identities derive from Terraform addresses so the picture updates instead of reshuffling, and a commit that changes nothing structural does not redraw anything. A node sitting more than twelve pixels from where the last sync left it is treated as hand placed and put back after the redraw, so a canvas you arranged for a steering committee stays arranged. Each regeneration also records how much of the previous diagram survived it, which is the number to check when a small source change returns a picture nobody recognizes.

FAQ

How many diagrams does an infrastructure migration need?

Three, with different lifetimes: a frozen before snapshot, a target that changes only by decision, and a current view generated from the repository. Most migration confusion comes from having several undated pictures and no rule about which one is authoritative.

How do I keep a before diagram from being overwritten?

Anchor it to a tag or a commit rather than to a live branch, and keep any hand-annotated version in a separate copy. A project synced to a moving branch regenerates from the code on every refresh, which is correct behaviour for the current view and wrong for a snapshot.

How do we prove a migration is actually finished?

Write a done-when clause that a generated diagram can settle: the legacy components no longer appear because they are no longer declared in the repository. That replaces a subjective milestone with a check anyone can run against the current view.

Should the target architecture diagram be generated from code?

No. The target describes infrastructure that does not exist yet, so there is no source to derive it from. It should be drawn and edited by people, versioned by revision number, and replaced by the generated current view once the code catches up.

What should a migration decision record contain?

The before snapshot with its date and commit reference, the target revision and who approved it, the reason for the migration, the constraints that shaped the plan, and an explicit definition of done. The current state does not belong in it, because a record should not change after it is written.