Skip to content
Delivery practice

Product Specification vs PRD: What to Write and When

By Sebastiaan Jansen · · 8 min read

A product specification describes observable behavior: inputs, outputs, rules, edge cases, and the checks that prove a build is correct. A product requirements document (PRD) describes the problem, who has it, the outcome you want, and what stays out of scope. Write the PRD while you are still deciding what to build. Write the specification once engineering, QA, and support need one shared description of correct behavior.

What a product specification includes

A software product specification is a contract about behavior. It says what the system does when a person, another system, or a timer acts, and what it refuses to do. The spec picks up wherever a developer would otherwise have to guess. If two engineers could ship different behavior from the same text, the spec isn't finished.

Behavior, data, and limits

A spec covers:

  • Trigger: who or what starts the behavior (a person, a webhook, or a clock).
  • Inputs: fields, types, which ones are required, and their limits (length, range, format).
  • Rules: the decisions the system makes, in the order it makes them.
  • Outputs: what the user sees, what gets stored, and what gets sent elsewhere.
  • Failures: validation errors, timeouts, conflicts, and partial success.
  • Permissions: who can run it, who can see the result, and what a stranger gets back.
  • Out of scope: behaviors you considered and rejected, one line each.

Name the product version. If superseded text still applies to a release in production, keep it and mark the header.

Every rule has to be something that can pass or fail. "The reminder goes out at 09:00 in the workspace timezone" can. "Reminders should feel timely" can't. Leave out market context, function names, and words like "intuitive". Keep one behavior per file.

A product specification template

Copy this and fill it in for one behavior:

  1. Title and version. The behavior and the release it targets.
  2. Actor. The person or system that starts it.
  3. Preconditions. What must already be true, or the flow doesn't start.
  4. Main flow. Numbered steps, one action per step.
  5. Alternate flows. Legitimate paths other than the happy path.
  6. Rules. Numbered statements that can pass or fail.
  7. Data written. Fields that get touched, and fields that must stay unchanged.
  8. Errors. The message, and whether it's safe to retry.
  9. Permissions. Allowed roles, and what everyone else sees.
  10. Acceptance checks. Given / When / Then, runnable without a follow-up.
  11. Open questions. Empty before you call the spec ready. As long as a question is open, the spec is a draft.

Add a feature flag only when turning it off restores the old behavior exactly. Name the flag, its default, and who may turn it on.

What the PRD covers instead

The PRD answers why this problem, why this slice now, for whom, what success looks like, and what you won't build. It can name a metric you'll watch after release. Describe users by role unless you have permission to quote a named person.

A PRD that spells out every validation message stops working as a decision document. Keep it short enough to read in one sitting, and link out to the specs. Use one PRD per outcome, plus one spec for each behavior that outcome needs. The product requirements document template stays readable when people and coding agents both work from it. The annotated PRD examples show how thin a useful PRD is next to the specs that follow it.

"No SMS in this slice" is a non-goal. "We might do mobile later" is a wish. Adding a forbidden field takes a new PRD decision, not a quiet edit. A success signal names an event and compares it with your own baseline. If you have no baseline yet, the first release just instruments the event.

When to write which document

Write the document that clears up the ambiguity you have right now. If you write both in full on day one, you freeze your guesses in place.

Moment Write Skip
You are still choosing the problem A PRD: problem, user, outcome, non-goals Field-level rules and error copy
You have a slice and a user flow A spec for that flow only A spec for the whole product
Engineering is about to start The spec plus acceptance checks A second PRD that restates the spec
A bug shows a rule was wrong An update to the spec, then the ticket A new PRD for a one-line rule fix
You are retiring the behavior A superseded mark and a pointer Leaving both docs as if both were true

Write the PRD first when the wrong build would be expensive: new surface area, money, permissions, or a workflow customers already use. You need the product specification as soon as two engineers would implement different behavior. Write the spec first only when everyone agrees on the outcome and the only thing missing is precision.

A backlog item is neither document. The Scrum Guide calls the Product Backlog an emergent, ordered list of what is needed to improve the product. So it's a queue. It doesn't record decisions or define behavior.

The definition of ready decides when a ticket can start: no open questions, checks exist, and the PRD's non-goals still hold. The definition of done decides when it can close: those checks passed, and the spec matches what shipped. If behavior drifted, update the spec in the same change or revert the code.

Worked example: invoice reminders

A B2B billing tool wants overdue invoices paid without someone chasing each one.

PRD, one page:

  • Problem. Finance staff copy due dates into a spreadsheet and send emails by hand. Invoices older than 14 days get chased only if someone remembers.
  • User. The account owner who sends invoices, on a team of about 5 to 30 people.
  • Outcome. Overdue invoices get a reminder without a person having to send it.
  • Success signal. The share of overdue invoices reminded within one day of crossing the rule, against your own baseline.
  • Non-goals. No collections agency, no late fees, no SMS, no change to the invoice total.

Spec for "Send overdue reminder":

  • Version. The release that introduces the daily job. Older releases send nothing.
  • Actor. A job at 09:00 in the workspace timezone, weekends included.
  • Preconditions. Status is Sent, due date is at least 7 days ago, balance is above zero, a billing email exists, and no reminder of this type exists yet.
  • Main flow. Select matching invoices. Email each one the number, amount, currency, and a hosted-invoice link. After the provider accepts the email, store invoice id, type, sent-at, and provider id, and add a timeline row. Leave the total, due date, and line items unchanged.
  • Rules. At most one reminder of this type per invoice. If the invoice is paid or voided before send, send nothing.
  • Errors. No billing email: skip, show "no billing email", leave sent-at empty. Provider timeout: retry twice, then record the failure without sent-at. Tomorrow's job may send if sent-at is still empty.
  • Permissions. Anyone who can view the invoice sees the row. Only a billing admin can turn the job off.
  • Checks. Due 8 days ago, email present: one email and one row. Next day: no second email. Paid: nothing stored. Missing email: "no billing email", sent-at empty.

The ticket links both documents and carries the checks into the test run. Build a requirements traceability matrix when several specs have to cover one PRD, or when an outsider will audit the links. For a single job, the ticket links are enough.

Late fees change what the customer owes, so they need a new PRD and a separate spec for calculation, display, and reversal. The reminder spec gets one extra line: "This job does not add fees."

How to keep both documents honest

Specs go stale when the code changes and the file doesn't.

  1. The ticket links the spec section it implements. A behavior change without a spec edit in the same change gets sent back.
  2. QA runs the checks from the spec. Any check the team accepts goes into the spec before release.
  3. Superseded rules stay readable, with a header pointing at the replacement. If you delete them, the old release has nothing to point to.

Whoever accepts the ticket owns the spec update. Whoever can change non-goals owns the PRD. Name them, even if it's the same person. In review, hold rules against checks, checks against non-goals, and errors against permissions. A rule with no check, or an error that reveals a hidden record, gets sent back.

If two people edit the same rule, the second write should fail until its author has read the first. When support quotes a sentence the code no longer implements, fix the document or the product that week.

Falrow is one place to run this loop. Meeting notes become reviewed tickets, stages carry the spec link, and coding agents plan from git under the team's workflow rules. Writes are version-checked, so a stale rule can't overwrite a newer one. How the delivery loop runs walks through the path from request to shipped work. Tickets, triage, and workflow rules is where the spec link should sit.

FAQ

Is a product specification the same as a PRD?

No. The PRD records the problem, the user, the outcome, and the non-goals. The spec records behavior for a chosen slice. Merge them and the file gets too long to decide from and too vague to test. Keep them separate and link both from the ticket.

Do I need a spec for every bug fix?

No. A typo or a null check that restores behavior the spec already describes needs no new document. Update the spec when the fix adds a timeout, a permission, or a case you used to reject. If the spec was wrong, correct it in the same change as the fix.

Who should write the spec, product or engineering?

Both, together. Product owns the outcome and the non-goals in the PRD. Engineering owns failure modes, data that must not change, and the checks. QA should be able to run those checks without someone explaining them privately. One named person accepts the spec.

Can a coding agent draft the spec?

Yes, as a draft. Give it the PRD, the code, and the template, and ask for rules and checks. A person still confirms timeouts, permissions, and non-goals. Reject any sentence that can't pass or fail. Store the accepted text next to the ticket.

More on delivery practice