Skip to content
Delivery practice

Requirements Traceability Matrix: Template and When You Need One

By Sebastiaan Jansen · · 9 min read

A requirements traceability matrix is a table that links each requirement to the design decision behind it, the ticket that implements it, the test that proves it, and the release that ships it. You read it to see what is covered, what has no test, and which earlier promise a new change might break. Teams with a written spec, a regulated buyer, or several people building the same product usually need one. A two-person team still inventing the product often does not.

The point is coverage. A promise with no row has no owner. A row with no test is a hope. And a test with no requirement may be protecting a behavior nobody asked for.

What a requirements traceability matrix records

An RTM is a many-to-many map. One requirement can need several tickets, and one ticket can satisfy part of several requirements. A single test usually covers one acceptance criterion, not the whole requirement.

Column What you put in it
Requirement ID Stable id, such as REQ-14. Never reuse a retired id.
Statement One testable sentence. "User can export invoices as CSV" works. "Export should feel fast" does not, until you name a limit.
Source PRD section, contract clause, or a support theme you accepted.
Priority Must, should, or later. Only Must blocks a release.
Design Spec section, ADR, or a short note on how.
Ticket Link to the issue. Do not paste status, because pasted status goes stale.
Test The check that would fail if this requirement broke.
Release Version where it is accepted as done. Blank until then.
Status Draft, building, verified, deferred, or dropped.

If the statement needs "and", split it. "Export invoices as CSV and email the file to finance" is two requirements, because they fail separately and ship separately.

Forward traceability runs from requirement to test and answers "did we build what we promised?" Backward traceability runs from a test or a change back to a requirement and answers "why does this behavior exist?" You want both. A forward-only map hides orphan tests, and a backward-only map hides forgotten requirements.

Where the rows come from

Rows start in the product requirements document, a contract, a compliance list, or a support theme you have accepted as a commitment. A brainstorm is a pile of wishes. A requirement is a wish someone accepted, wrote down so a test can fail, and gave an id.

To decide, ask whether you would delay a release because this is missing. If yes, it gets a row. If no, it is a note on the ticket.

When you need a traceability matrix

Build a traceability matrix when a customer or auditor can ask you to show that a requirement shipped, along with the test. You also need one when more than one team shares a spec, when you are replacing a system and must not drop a behavior users rely on, or when release scope is contractual. The same goes for teams whose bugs keep turning out to be missing requirements found after the code was written.

Skip it for a spike, a visual experiment, or a one-week fix with a single owner. Write the requirement on the ticket, test it, and move on.

Regulated work is the classic case, but the same table helps when a buyer sends a security questionnaire. Those questions are requirements whether you call them that or not.

A sheet is enough until people stop updating it because it is a second place to type. At that point, put the id on the ticket and treat the matrix as a view.

A requirement traceability matrix template

Use one line per accepted requirement. Someone mentioning an idea in chat is not a reason to add a row.

ID | Requirement | Source | Priority | Design | Ticket | Test | Release | Status
REQ-01 | Admin can export paid invoices as CSV for a chosen month | PRD §4.2 | Must | Spec §3.1 | INV-120 | export_csv_test | 1.4 | Building
REQ-02 | CSV columns are id, customer, issued date, currency, total | PRD §4.2 | Must | Spec §3.1 | INV-120 | export_columns_test | 1.4 | Building
REQ-03 | Over 5,000 invoices, export is refused with an error | PRD §4.3 | Should | Spec §3.2 | INV-134 | export_limit_test | | Draft
REQ-04 | Finance receives the file by email | Support theme, not accepted | | | | | | Dropped

REQ-04 stays on purpose. If you delete a dropped row, the next review will look as if the requirement never existed.

  1. IDs are stable. If REQ-03 changes meaning, retire it and add REQ-05.
  2. If everything is Must, nothing is. Priority is a release decision.
  3. Ticket and test are links or named scripts. "QA will check" counts as an empty cell.
  4. Update the row when you accept the definition of done. A matrix nobody updates shows coverage you do not have.
  5. At release cut, list every Must row that is not Verified.

Drop columns nobody filters on. If there is no design doc, point Design at the ticket. If you don't name versions, put the cycle name in Release. For the gap list, filter to unverified rows, then scan for tests with an empty requirement id. A missing id is fine on a refactor. It becomes a problem when new behavior has no row to protect it later.

How to fill it without a second job

Fill in columns as the facts appear.

While you write the spec, add the id, statement, source, and priority, and leave ticket, test, and release blank. This is the cheap moment to split a muddy sentence. The product specification holds the how; the matrix only points at it.

Once the ticket is ready, link it. If API and UI ship separately, use two tickets or REQ-01a and REQ-01b, split along the lines you will test. Ready means the id is on the ticket, the check is named, and no open question would change the row, which matches a definition of ready.

When the test exists, link it before the work is done. A green test that is not on the row does not count, and a Verified row with a blank test cell is how reviews go badly.

At release, fill in Release only for rows you are willing to defend, and mark the rest Deferred on purpose.

Verified means the named test passed on the build you are releasing and someone other than the author accepted the statement. A green run on another branch is not enough. For a manual test, store the date, build, and person. When CI keeps the history, the test name is enough.

Worked example: invoice export

The PRD promises a monthly CSV, stable columns, and a cap so one huge account cannot take the export down.

ID Requirement Ticket Test Status
REQ-01 Admin exports a chosen month as CSV INV-120 export_csv_test Building
REQ-02 Columns are id, customer, issued date, currency, total INV-120 export_columns_test Building
REQ-03 Over 5,000 invoices, export is refused with an error INV-134 export_limit_test Draft
REQ-07 Totals match the invoice, in minor units INV-141 export_totals_test Verified on main, not in 1.4

REQ-01 and REQ-02 share INV-120. If someone closes the ticket because "export works", column order is still unproved, so both tests have to pass. REQ-03 is still Draft. If 1.4 must include the cap, the release is not ready; if the cap is only Should, you can ship and say so. REQ-07 passed on main but is missing from the 1.4 branch, so its release cell stays blank. A green main build does not make 1.4 done.

Later, finance reports that credit notes were dropped. If credit notes were never in the column list, add REQ-08 and prioritize it. If they were in the statement and the fixture never included one, the row was marked more complete than it was. Either way, the new test should fail on the old build and pass on the new one before you mark the row Verified again.

Months after that, someone wants a faster export that drops the cap "for now." REQ-03 is the objection, and it has a test name on it. You can still drop the cap, but you change the row in writing.

Tickets, releases, and the index

The matrix is an index: the ticket holds the work and the PRD holds the agreement. On the ticket, store ids and acceptance checks. On the PRD, store the narrative, the out-of-scope list, and the ids. When wording changes, change it in one place.

The release gate is a query: which Must rows for this release are not Verified? Cutting scope in writing is ordinary release management, and Deferred is a status you can show a customer.

A bug in an existing requirement does not get a new row. Point the ticket at the id and add a regression test. A newly accepted promise does get a row. A library upgrade often has no requirement at all, and that is fine.

If you expect a sheet to rot, put the id and the test link on the ticket, and block Verified while a Must item has no test. That is still a requirements traceability matrix. Falrow keeps requirement, ticket stage, and acceptance on one record, so the matrix is a filter. The ticket workflow and the path from request to shipped work are that filter. Jira, Linear, Azure DevOps, or a sheet work too, as long as the id is required before a Must item is called done. When the field is optional, coverage ends up living in people's memory.

Common failures

Open the row when you accept the promise, not after the code lands. Split epics until a test could fail; "Billing v2" is not verifiable. Leave in-progress rows at Building. Link the test instead of pasting the plan. Keep dropped ids. Trace the failure you promised, which in the export example is REQ-03.

If the file is already a mess, do not try to rewrite it in an afternoon. Starting today, allow no new Must requirement without an id, and backfill only the Must rows in the next release.

What this does not replace

A matrix does not prioritize. It shows what a yes will cost, and priority still gets decided on the roadmap and at the release cut.

It does not design the system either. "See spec §3.1" is a pointer, and if that section is empty, so is the cell.

It also cannot make up for weak tests. If the CSV test only checks that the file is non-empty, REQ-01 can read Verified while the file is wrong. Tighten the test.

Someone still has to refuse scope that has no id. Forty requirements might turn into eighty testable rows, which is fine. Hundreds of vague lines are just a backlog under a more formal name. Whatever tool you use, the question is the same: which accepted requirements pass on this build?

FAQ

What is a requirements traceability matrix?

It maps each accepted requirement to its source, the work that implements it, the test that proves it, and the release that includes it. You use it to see gaps before you ship, and later to explain why a behavior exists. It is coverage bookkeeping, not a plan of who does what this week.

What is the difference between an RTM and a test plan?

A test plan says how you test: the environment, the data, who runs what, and which kinds of tests you run. The RTM says which requirement each test protects. A plan can exist with no requirement ids, but an RTM with no test links is unfinished. Keep the plan short and point the matrix at specific cases.

When should you not use a traceability matrix?

Skip it for spikes, visual experiments, and small fixes with one owner and no promise to an outsider. Also skip it before the requirement is accepted, because tracing a brainstorm freezes ideas that should still be cheap to drop. Start when a sentence is a commitment you might have to prove.

Who maintains the matrix?

One person owns the rules: stable ids, a test before Verified on Must rows, and dropped rows kept in the file. On a small team that is often the product manager or the tech lead. Authors still fill in the ticket and test cells for their own work. Without a named owner for the release check, the status column drifts.

More on delivery practice