Most postmortem templates die the same way: twelve sections, three of them philosophical, and an engineer pasting “n/a” so they can go home. A template that works is short enough to finish while memories are fresh, specific enough that action items are testable, and boring enough that nobody performs blame theater.

This article gives a one-page template, a filled example from a synthetic connection-pool incident (aligned with the other Stack Inside labs), and rules for follow-up that do not depend on heroics.

Why long templates fail

Heavy sectionWhat happens in practice
Five-whys essayTurns into speculation without evidence
“Customer love” paragraphsWritten by PM later, ignored by eng
Huge timeline tableEmpty until someone reconstructs from partial logs
Blameless manifesto every timeRitual text, zero new information

You still need blameless culture. You do not need to re-derive it in every document. Put culture in the team handbook; put facts, impact, and fixes in the postmortem.

Minimal template (copy-paste)

# Postmortem: <short name>

- **Status:** draft | final
- **Authors:**
- **Incident window (UTC):**
- **Severity:**
- **Services:**
- **Customer impact:**
- **Detection:**
- **Resolved by:**

## 1. Summary (5–8 lines)
What broke, who felt it, how it was fixed.

## 2. Impact
- User-visible symptoms:
- Approximate scope (tenants / % traffic / duration):
- Hard numbers if available (error rate, lag, $):

## 3. Timeline (UTC)
| Time | Event |
| --- | --- |
| | |

## 4. Technical root cause
What mechanism failed? Link graphs, queries, configs, PRs.

## 5. Why it escaped detection
Monitoring, tests, process gaps. No personality analysis.

## 6. What worked
Keep this short; it prevents only-doom documents.

## 7. Action items
| ID | Action | Owner | Due | Done? |
| --- | --- | --- | --- | --- |
| PM-1 | | | | |

## 8. Open questions
Only items that still need investigation.

That is enough for most backend incidents. Add appendices only when regulators or enterprise customers require them.

Filled example (synthetic lab incident)

The following is a worked example for documentation practice. It is not a claim about a specific employer’s outage. Numbers match the style of the connection-pool and structured-logging labs.

# Postmortem: orders-api pool exhaustion

- **Status:** final
- **Authors:** Stack Inside lab
- **Incident window (UTC):** 2026-08-01 14:05 – 14:41
- **Severity:** SEV-2
- **Services:** orders-api, checkout-web
- **Customer impact:** elevated HTTP 503 on pay; checkout failures
- **Detection:** error-rate alert on route POST /v1/orders/{id}/pay
- **Resolved by:** reduce pool size + cap HPA replicas; recycle pods

## 1. Summary
orders-api instances used pool_size=25 with 12–18 replicas under autoscale.
Theoretical DB demand exceeded usable max_connections. Clients saw 503 with
error_code=db_pool_timeout. Mitigation: set pool_size=11, max replicas=12,
and restart pods to drop leaked idle clients. Durable fix tracked in PM-1–PM-4.

## 2. Impact
- Symptoms: pay button failures, 503 JSON body, retries in web client
- Scope: ~35 minutes; estimated 8–12% of checkout attempts erroring at peak
- Numbers (synthetic): p95 latency 1.2s → dominated by db_wait_ms; 5xx peak 9%

## 3. Timeline (UTC)
| Time | Event |
| --- | --- |
| 14:05 | HPA scales orders-api 12 → 18 during marketing traffic |
| 14:07 | DB Threads_connected approaches max; app pool wait rises |
| 14:09 | Alert: 5xx ratio on pay route |
| 14:18 | On-call filters logs: error_code=db_pool_timeout |
| 14:27 | Identify instances × pool_size > usable connections |
| 14:33 | Ship config: pool 11, HPA max 12 |
| 14:41 | Error rate back under SLO; incident closed |

## 4. Technical root cause
Fleet connection budget violated: instances × pool_size > max_connections − reserved.
Autoscaling multiplied the oversubscription. Logging showed db_wait_ms ≈ latency_ms.

## 5. Why it escaped detection
No deploy-time check that max_replicas × pool_size fit the database budget.
Connection metrics existed but alerted at ceiling, not at unsafe theoretical demand.

## 6. What worked
Structured logs with error_code + request_id let on-call skip host SSH.
Pay route SLO alert fired within minutes.

## 7. Action items
| ID | Action | Owner | Due | Done? |
| --- | --- | --- | --- | --- |
| PM-1 | Add CI script: simulate.mjs fails if demand > usable | platform | 2026-08-08 | yes |
| PM-2 | Dashboard: theoretical demand = replicas × pool | platform | 2026-08-08 | yes |
| PM-3 | Alert when theoretical demand > 0.8 × usable | platform | 2026-08-15 | yes |
| PM-4 | Doc: pool sizing table in service runbook | orders | 2026-08-10 | yes |

## 8. Open questions
None for this incident. Separate review: should pay use a pooler service?

Notice the action items are checkable. “Be more careful” is not an action item.

Follow-up mechanics

  1. Track actions in the same system as other engineering work (issues with IDs). The table is an index, not a parallel universe.
  2. Review open PM actions weekly for two weeks after SEV-2+, then fold into normal backlog grooming.
  3. Close the postmortem only when owners accept actions—not when the Google Doc looks pretty.
  4. Verify fixes with the same signals that caught the incident (alert, log query, budget script).

Anti-patterns

  • Blame by proxy: “the on-call should have known.” Rewrite as a missing test or alert.
  • Action item theater: twenty tickets, zero owners, none scheduled.
  • Timeline fan-fiction: if logs do not support a line, mark it unknown.
  • Tool worship: switching log vendors mid-incident does not belong as the primary fix when the budget math is wrong.

What we removed on purpose

Compared to enterprise templates, this one drops:

  • multi-page customer communication drafts (own those elsewhere)
  • exhaustive five-whys beyond evidence
  • mandatory “lessons for leadership” essays
  • screenshots of every dashboard panel (link graphs instead)

If legal needs more, attach an appendix. Do not force every weekend incident through a 15-page gauntlet.

Summary

A postmortem engineers will fill out is short, factual, and action-oriented. Use a stable skeleton; fill impact and timeline from logs; write a root cause that names a mechanism; close with owned, dated actions. The synthetic example above is intentionally aligned with the pool-math and structured-logging labs so you can practice the whole loop—detect, diagnose, document, prevent—without waiting for a real SEV to learn the paperwork.