Topic: architecture decision record example

Architecture Decision Record Example: Postgres vs MongoDB

Most ADR examples on the web are abstract — "Foo vs Bar" with square-bracket placeholders. Here's a concrete one, written as you'd actually commit it. Every section filled, sourced from a real ChatGPT conversation.

TL;DR

The example below is ~230 words, fits on one screen, and covers a decision most SaaS teams make in their first year: Postgres vs MongoDB for a mixed-workload app. It's written in the Nygard format with the Alternatives and Stakeholders extensions. Copy it, change the names, commit.

The ADR

# 0003. Use Postgres as the primary datastore

**Date:** 2026-02-14
**Status:** Accepted
**Deciders:** @ana (CTO), @rob (staff eng)
**Supersedes:** —
**Superseded by:** —

## Context

We're building a metrics-and-billing backend for a 20-seat B2B SaaS.
Expected load at 12 months: ~10M rows, ~200 QPS peak, single-region.
The workload is mostly relational (customers, subscriptions, invoices,
line items, usage events) with one write-heavy table (raw usage events).
We need ACID for billing, joins for reporting, and something the team
already knows. Timeline: ship in 8 weeks.

## Decision

We will use Postgres 16 as the primary datastore, managed on RDS.
Raw usage events land in a partitioned table with monthly partitions
and a 90-day retention policy. Reporting goes against the same DB
with read replicas when QPS requires it.

## Alternatives considered

- **MongoDB Atlas:** Rejected. Billing needs multi-document ACID
  (invoice + line items) and Mongo's transactions have sharp edges on
  sharded clusters. Team has zero Mongo operational experience.
- **DynamoDB:** Rejected. Access-pattern modeling is painful for ad-hoc
  reporting; would force us to maintain a separate OLAP store early.
- **ClickHouse for events + Postgres for rest:** Rejected. Nice at
  scale, premature at our stage. Add it in year two if QPS demands.

## Consequences

### Positive
- One system to operate, back up, monitor.
- Team familiarity; interviewable hire pool is huge.
- Strong ACID for billing paths.

### Negative
- Partition maintenance for usage events is manual until we script it.
- Some read queries will need replica routing by month 9.

### Neutral
- Schema migrations via a standard tool (Prisma Migrate).

## Links

- PR: #42 (schema)
- Original discussion: ChatGPT conversation 2026-02-14 10:04 UTC
- Related: [0007. Usage-event partitioning strategy](0007-…)

What the original chat snippet looked like

This ADR was extracted from a 23-message ChatGPT thread. The decision emerged in messages 17–19 of the conversation. Here's the signal the extractor latched onto:

user:      Okay, I think we're going with Postgres. Mongo's
           multi-doc transactions are not worth the ops cost, and
           we don't have sharding expertise in-house. What else
           should I capture in the ADR?

assistant: You've covered the main trade-offs. I'd add:
           1. The "do nothing / use what we have" baseline — even
              if you have nothing, document why Postgres over
              SQLite-for-dev-only, etc.
           2. Billing-specific ACID requirements (invoice +
              line-item atomicity) — that's the killer argument.
           3. Partitioning strategy for usage_events, since that's
              the table that will dictate scaling first.

user:      Good. One more thing: we looked at ClickHouse for events
           briefly — call it out in Alternatives Considered so we
           don't revisit it in Q3.

The extractor picked up the "we're going with" phrase as a high-confidence decision marker, scanned backward for the alternatives discussed earlier in the thread, and cross-referenced "ClickHouse" and "DynamoDB" as rejected options. Timestamps on the original messages became the ADR date.

How WhyChose generated this

This is the exact output shape WhyChose produces: ADR sections filled from the chat itself, in the Nygard format, with the source conversation linked for audit. The extraction uses regex heuristics first (cheap, deterministic), then an LLM pass to normalize phrasing and pull alternatives. You can run the same extraction locally with the open-source CLI — the example above came from running node bin/extractor.js sample-chatgpt.json --format md on a sanitized real conversation.

Get early access

Related questions

How long should an ADR be?

Under 250 words for the core sections (Context, Decision, Alternatives, Consequences). Longer than that and nobody reads it; shorter and the trade-offs don't come through. The example above is 230 words, and that's about the upper limit.

Should I mention the ChatGPT conversation in the ADR itself?

Yes, with a private link. The chat is the evidence behind the decision — in six months, the link is what lets a reviewer re-check your reasoning. Store the conversation ID (not the full transcript) in the Links section.

What if the decision later turns out wrong?

Don't edit the original ADR. Write a new one ("ADR 0042. Reverse course on datastore — move usage events to ClickHouse") that supersedes the old one. The history is the point; a decision log you can edit post-hoc has zero audit value.

Further reading