The doc was good. Two engineers had read it, the design was sound, and the rollout plan had a real kill switch in it. In the review somebody asked how often the timeout actually fired and for which customers, because the whole design hung on it being rare and recoverable. The author said he was fairly sure it was rare. It had come up in a support escalation back in April and the number in the doc, occasionally, was the word from that thread.
The design shipped. It turned out occasionally meant eleven accounts, four of them on the largest plan, and the recoverable path assumed a retry that those four could not use. None of that was hidden. It was sitting in closed HubSpot tickets from March through May, and reconstructing it would have taken an afternoon that nobody had budgeted for a document already two days late.
This guide gives you the eight sections, an alternatives section that is worth writing, a worked example, a design review checklist, and a copy-paste software design document template at the bottom.
In this article
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
What a Software Design Document Actually Does
A software design document is the written argument for how something will be built, produced before it gets built. It exists to make a decision reviewable. Any engineer can describe the system they intend to write. Far fewer can say which two of the three plausible approaches they rejected and what it would take to change their mind, and that second thing is the entire product of the exercise.
Three things it is not, and each confusion produces a different useless document:
It is not a description of the final system
A doc that only says what the code will look like when it is done gives a reviewer nothing to push against. Every sentence reads as settled, so the comments come back as typo fixes and a thumbs up. The reader cannot tell which parts were deliberated and which were the first thing that came to mind, and those two categories need very different amounts of scrutiny.
It is not documentation
Documentation describes how the system works now and has to stay true. A design doc describes what was decided on a date, with the information available on that date, and it is allowed to age. Merging the two produces a document that is maintained badly and trusted less each quarter, which is worse than having neither.
It is not a PRD with diagrams in it
A PRD argues that a thing is worth building. A design doc assumes that argument is settled and argues about the how. When one document tries to do both, the product case gets the space and the implementation gets a paragraph, because the product case is the part that feels contested when it is being written.
The Software Design Document Template: Eight Sections
Eight sections, in this order. Anything past these tends to be written once and never read, and a section that is empty on half your team's docs makes the whole template look optional.
- 1
1. Context and problem
What is broken or missing, for whom, and how you know. This is the section that gets written fastest and decays first, and the rest of the doc is only as good as it is. Put numbers in it: how often, how many accounts, since when. A problem statement written in adjectives produces a design scoped by vibes, and the review has nothing to check the proposal against.
- 2
2. Goals and non-goals
Three or four goals, stated as observable outcomes rather than as activities. Then the non-goals, which are the more valuable half. Non-goals are what let a reviewer's reasonable question get answered with a decision instead of with scope. Almost all mid-project growth arrives as a sensible-sounding suggestion during review, and a written non-goal is the cheapest thing that stops it.
- 3
3. Current state and constraints
How the relevant part of the system works today, plus what you are not free to change. Deadlines, compatibility promises, data volumes, the service that cannot take more load, the migration that has to run online. Constraints are what make one design better than another. A doc without them reads as though every option was available, which invites reviewers to propose the option you already ruled out on the first day.
- 4
4. Proposed design
The shape of the solution, in enough detail that a competent engineer who was not in the room could build it. Components, responsibilities, and how they talk. A diagram helps and does not substitute. The written version is what carries the reasoning, and the reasoning is what a reviewer engages with.
- 5
5. Alternatives considered
Two or three real options with the reason each was rejected. The quality test is whether at least one of them still looks tempting after you explain why it lost. This is the section that converts the doc from a description into a decision record, and it is the one that pays off longest, because it is what answers the same question when somebody asks it again in a year.
- 6
6. Data model and interfaces
New tables, changed columns, the migration and whether it can run online, plus the API or event contracts that change and who consumes them. Be specific about backward compatibility. This section is where a design that is fine in isolation turns out to be expensive, because the cost is nearly always in the things already depending on the current shape.
- 7
7. Failure modes and rollout
What breaks, what the user sees when it does, how you would know, and how you would undo it. Then the rollout: flag, percentage, order, and the specific signal that would make you stop. A rollback plan that says revert the deploy is not a rollback plan once a migration has run, and that gap is worth finding while writing rather than at two in the morning.
- 8
8. Open questions and reviewers
The things you genuinely do not know, listed rather than smoothed over, plus named reviewers with what each is being asked to check. A doc with no open questions is either trivial or dishonest. Naming the question is also how you find out that the person who could answer it in five minutes was never going to read the doc unprompted.
Design Doc vs PRD vs Technical Documentation
Three documents, routinely merged, with genuinely different owners, audiences, and lifespans. Merging any two costs you the weaker one.
Owned by whoever is accountable for the outcome, read by everyone, and frozen when the work starts. Its evidence is about demand: who asked, how often, and what it is worth. See the PRD template for the sections and the evidence problem that comes with them.
Owned by the engineer doing the work, read by other engineers and by whoever will be on call for it, and frozen when the work ships. Its evidence is about constraints: what actually broke, at what scale, and for whom. That is a different question from the PRD's and it is answered from different sources.
Owned by whoever maintains the system, read by whoever touches it next, and maintained indefinitely. This is the only one of the three that has to stay true, which is exactly why it should not be the same file as the other two. Anything in a design doc that must remain accurate belongs here instead.
A useful rule: if a sentence will need editing when the code changes, it belongs in technical documentation, not in the design doc. Design docs get a date and a status and then they stop moving.
How to Write a Software Design Document
The order you write the sections in is not the order they appear in, and writing them in document order is the most common way a design doc ends up as an expensive description.
- 1
1. Write the problem statement and go find the numbers
Write what you believe the problem is, then go and check it before writing anything else. This step is skipped almost universally and it is the one that determines whether the rest of the document is aimed at anything real. If the number in your problem statement came from memory of a conversation, mark it as such in the draft so a reviewer knows what weight to give it.
- 2
2. Write the non-goals next, while you still resent them
Non-goals are easiest to write before you are attached to a design, because at that point excluding something costs you nothing. An hour later you will have a solution in mind and the non-goals will quietly reshape themselves around it.
- 3
3. Write the alternatives before the proposal
Genuinely consider the options first, on the page, and then pick. Written in the other order the section becomes a justification exercise, and everyone can tell. The tell is that the rejected options are all straw and the reader learns nothing about the tradeoff.
- 4
4. Draft the design, then write the failure modes and revise
Failure modes are a design review you run on yourself, and they routinely change the proposal. Writing them last as a formality wastes the most useful section in the document. Writing them and then going back to edit section four is the point.
- 5
5. Name reviewers and what each one is checking
Send it to three named people with a specific question each, not to a channel. A doc posted to a channel gets read by whoever has a slow afternoon, which is not correlated with who knows the thing you are unsure about.
The proposal is not the output. The rejected alternative that still looks tempting is the output, because that is the one somebody will propose again in a year.
Software Design Document Example: A Compressed One
Structure advice is easy to agree with, so here is a short version with the proportions right. Note how much room the alternatives and the failure modes take compared to the proposal.
Context. The CSV export builds the full result set in memory and streams it at the end. Above roughly fifty thousand rows the request exceeds the sixty second gateway timeout and the user gets a generic error with no partial file. In the last ninety days this fired for eleven accounts, four of them on the largest plan, concentrated in the first three business days of each month.
Goals. Exports of any size complete or fail with a specific message. No regression in export latency below ten thousand rows. Non-goals. We are not adding scheduled exports, we are not changing the export's column set, and we are not fixing the same pattern in the reporting endpoint, which has different constraints and gets its own doc.
Constraints. The gateway timeout is fixed at sixty seconds by the platform and cannot be raised per route. Two of the four large accounts pull the export through the API on a schedule, so the response shape cannot change without notice.
Proposed design. Stream rows in batches of five thousand from a keyset-paginated query, writing to the response as each batch resolves. Keep the existing synchronous route and shape.
Alternatives considered. A background job writing to object storage with an email link is the more standard answer and it was rejected on the two API consumers, who would need to change their integration and were not going to on our timeline. It remains the right long-term shape and this design is deliberately compatible with adding it later. Raising the batch size without keyset pagination was rejected because the offset scan is what costs the time, so it moves the ceiling without removing it.
Data model and interfaces. No schema change. The query gains a composite index on account and created-at, added online. The response shape is unchanged for every consumer.
Failure modes and rollout. A batch failure mid-stream produces a truncated file with a valid header, which is worse than an error because it looks like success, so each response gets a terminating footer row and the client-side check for it ships first. Behind a flag, enabled for internal accounts, then the four large accounts, then everyone, with a stop signal on any increase in truncated responses.
Open questions. Whether the two API consumers parse strictly enough that a footer row breaks them. Reviewers. Priya on the query plan, Marc on the rollout because he carries the pager, and the support lead to confirm the eleven-account figure is still current.
That last reviewer is the interesting one, and the next section is about why.
Why the Context Section Is the One That Decays
Sort a year of design docs by which section aged worst and it is never the design. The proposal, the interfaces, and the failure modes stay legible because they describe a system that engineers can go and read. The context section decays, because the evidence behind it lives somewhere the author cannot search.
It is worth being precise about where. The claim eleven accounts, four of them on the largest plan, concentrated at month end, is not knowable from the codebase. It is assembled out of support tickets that closed months ago, in the customer's own words, spread across a help desk that engineering does not open. So the number in the doc is whatever somebody remembered from an escalation thread, and it goes unchallenged in review because nobody in the room has a cheaper way to check it.
That is the same broken trail that makes the evidence section of a PRD impossible to reconstruct, that leaves the what-shipped slide in a QBR to be rebuilt by hand every quarter, and that quietly stalls the issue rows in a risk register.
The version that holds up is mechanical, and all of it depends on the link being recorded when the work is filed rather than reconstructed when the doc is written:
File the engineering issue from the ticket, not alongside it
An issue created from the ticket that reported the problem carries the customer's own description of it. An issue typed fresh into the tracker carries an engineer's paraphrase of a paraphrase, and the specificity that would have sharpened the problem statement is gone at the first retelling.
Attach the reporting accounts at the moment of escalation
A context section that says eleven accounts, four on the largest plan is worth several times one that says some customers. Recording the requesting account on the engineering issue when it is filed is what makes that count a lookup later. Linear's customer requests model exists for this, and the value of it shows up about a month after anyone starts using it.
Keep the reporters attached through the fix
The same list that sharpens the problem statement is the list you need when the work ships. If it survives from ticket to issue to release, then writing the release notes and telling the affected accounts are the same short job rather than two, and only the first of two ever reliably gets done.
Let the support lead review the problem statement
Naming a non-engineer as a reviewer on the context section only works if checking it is cheap. If confirming a number means reading eight closed tickets by hand, the review comes back as looks right, which is the same as no review. Make it a search and the third reviewer becomes the most useful one on the doc.
A problem statement a reviewer can actually check
- Every escalated issue carries the ticket that raised it
- The affected accounts travel with the issue
- Counting affected accounts takes seconds
- The customer's own wording survives to the design review
- Shipped fixes map to the people still waiting
A problem statement everyone nods at
- Numbers come from memory of an escalation thread
- Affected accounts are a guess
- Checking the figure means reading closed tickets by hand
- The design is scoped against a paraphrase
- Customers hear about the fix months late, if at all
That table is not really about design docs. It is about whether the handoff from support to engineering left a durable trail, and the design review is simply the moment a team finds out it did not. The same gap turns up in defect management, in how to get bugs fixed faster, and in managing feature requests from support to engineering.
For teams where support runs on HubSpot Service Hub and engineering runs on Linear, IssueLinker is what keeps that trail intact. A ticket becomes a linked Linear issue in one click with the customer's own wording carried across, the requesting account travels with it, and status and comments sync both ways, so the number in your problem statement is something you look up rather than something you remember. The Linear HubSpot integration guide covers how the two-way sync works.
Write problem statements you can defend in review
If support runs on HubSpot Service Hub and engineering runs on Linear, IssueLinker links the customer ticket to the engineering issue and syncs both ways, so how many accounts and in whose words are a search rather than an afternoon.
Technical Documentation Template: What Happens After the Design Ships
A design doc freezes. Something still has to stay true, and the mistake is trying to make the frozen document do that job. When the work ships, move the durable parts out into technical documentation and stamp the design doc closed.
A technical documentation template for a service or component needs far less than most teams put in it:
- 1
What this is and what it is responsible for
Two or three sentences. The most useful line is usually the boundary: what this component deliberately does not handle and which one does instead. That is what stops the next person from adding the wrong thing here.
- 2
How to run it and how to change it safely
Local setup, the tests that matter, and the specific things that break when changed carelessly. This is the section that saves the most hours and it is written best immediately after somebody breaks one of those things.
- 3
Interfaces and their consumers
What it exposes and who depends on it. Naming the consumers is the part that is skipped and the part that determines whether a change gets made confidently or nervously.
- 4
Operational notes and known sharp edges
Where the logs are, what the alerts mean, and the failure modes that already happened. Link the design doc here rather than copying it in, so the history is one click away and does not need maintaining.
Keeping documentation short is not laziness, it is what makes it maintainable. A page that takes ten minutes to update after a change gets updated. A page that takes an hour gets a note added to the bottom saying parts of this may be out of date.
The Design Review Checklist
Run this before sending the doc out. It takes about ten minutes and it catches most of the ways a design review turns into a formality.
Before you send it for review
- The problem statement has numbers, and you know where each one came from.
- Any figure that came from memory is marked as unverified in the draft.
- There are non-goals, and at least one of them is uncomfortable.
- At least one rejected alternative still looks tempting after the explanation.
- The rollback plan survives the migration having already run.
- Every interface change names the consumers that depend on it.
- There is at least one honest open question.
- Reviewers are named individuals with a specific question each.
- Someone outside engineering is checking the problem is still the real problem.
The first two and the last one are the items that fail, and they fail structurally rather than through carelessness.
Mistakes That Make a Design Doc Ceremonial
Four patterns account for most design docs that get written carefully and then change nothing.
Alternatives that were never real
Three options where two are obviously bad. Everyone reading can tell the choice came first, so the section carries no information and the review skips it. The fix is to write the alternatives before picking, which feels slower and is the only version that works.
A problem statement made of adjectives
Slow, unreliable, and painful are not scopeable. Without a number, the design cannot be checked against anything and the review becomes a conversation about taste. This is the single highest-leverage sentence in the document and it is routinely the one written from memory in the last ten minutes.
Writing it after the code
A doc produced to satisfy a process step, once the branch already exists, is a description with a review attached. Nobody expects it to change anything and it does not. If the work is genuinely too small to design up front, skip the doc rather than backfilling one.
Trying to keep it current
Six months of edits later, the doc is neither an accurate record of what was decided nor a reliable description of the system. Freeze it with a date and an outcome, and put anything that must stay true in the technical documentation instead. A frozen doc that is honestly historical is more useful than a living one that is quietly wrong.
The thread through all four is that a design doc is judged by whether it changed the design. If the code would have come out the same without it, the document was a description, and describing a system is much easier than deciding one.
Copy-Paste Software Design Document Template
Paste this into a doc, a wiki page, or the repo next to the code. It is deliberately plain, because the formatting is not what makes it useful.
SOFTWARE DESIGN DOCUMENT: [ title ]
Author: [ one name ] Date: [ date ]
Status: [ draft | in review | approved | shipped | superseded by ... ]
Reviewers: [ name ] - [ what they are checking ]
[ name ] - [ what they are checking ]
[ name ] - [ what they are checking ]
1. CONTEXT AND PROBLEM
What is broken or missing, for whom, and how we know.
[ how often ] [ how many accounts ] [ since when ]
Source for each number: [ ticket search | dashboard | memory, unverified ]
2. GOALS AND NON-GOALS
Goals
- [ observable outcome, not an activity ]
Non-goals
- We are NOT [ the thing people will ask about in review ]
3. CURRENT STATE AND CONSTRAINTS
How it works today: [ ... ]
Fixed constraints: [ deadline | compatibility | data volume | load ]
4. PROPOSED DESIGN
[ components, responsibilities, how they talk ]
[ diagram optional, prose required ]
5. ALTERNATIVES CONSIDERED
Option A: [ ... ] Rejected because [ ... ]
Option B: [ ... ] Rejected because [ ... ]
( if none of these still look tempting, they are not real alternatives )
6. DATA MODEL AND INTERFACES
Schema changes: [ tables, columns, migration, online or not ]
Interface changes: [ contract ] Consumers: [ who breaks ]
Backward compatible? [ yes | no, and the plan ]
7. FAILURE MODES AND ROLLOUT
What breaks: [ ... ]
What the user sees: [ ... ]
How we detect it: [ signal ]
How we undo it: [ and does this survive the migration? ]
Rollout: [ flag | order | stop signal ]
8. OPEN QUESTIONS
- [ something you genuinely do not know ] Owner: [ name ]
CLOSED
Shipped on [ date ]. Outcome: [ one line ].
Durable parts moved to: [ link to technical documentation ]
This document is frozen and is not maintained.
Keep the closed block at the bottom rather than deleting the doc. It costs nothing, and a year later it is the only record of why the system is shaped the way it is. That is worth more than the document was during the project, and it is the input to the next one.
If the same class of problem shows up in three consecutive design docs, stop designing around it and give it a root cause analysis of its own. Recurrence across projects is a signal about the system rather than about any one design.


