<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/9-30-days-system-design-question-anwm4ygmc" -->

---
title: 9/30 Days System Design Question | daily.dev
description: A system design challenge presents a Postgres monolith handling 8K writes/min and 40K reads/min where read and write models require fundamentally different...
canonical: https://daily.dev/posts/9-30-days-system-design-question-anwm4ygmc
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: 9/30 Days System Design Question | daily.dev
og:description: A system design challenge presents a Postgres monolith handling 8K writes/min and 40K reads/min where read and write models require fundamentally different...
og:url: https://daily.dev/posts/9-30-days-system-design-question-anwm4ygmc
og:image: https://api.daily.dev/og/posts/AnwM4yGmC.png
og:image:alt: 9/30 Days System Design Question
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 9/30 Days System Design Question

**[Joud Awad](https://daily.dev/sources/iac4jsbu0lv8wbsc85fsh)** · [@joudawad](https://daily.dev/joudawad) · 2 min read · 400 upvotes · 68 comments

## Summary

A system design challenge presents a Postgres monolith handling 8K writes/min and 40K reads/min where read and write models require fundamentally different data shapes. Four architectural options are evaluated: full CQRS with separate read/write stores, read replicas, denormalizing the write schema, or adding GraphQL with DataLoader. Readers are asked to pick the best approach and justify their reasoning, with the post hinting that one option is a senior engineer trap that works short-term but fails later.

## Content

Your orders service is a Postgres monolith doing 8K writes/min and 40K reads/min.

Same tables. Same schema. Everything's grinding.

The write side needs a normalized schema — orders, line_items, payments, shipments, addresses. Clean FKs, ACID, no duplicated data. The read side wants the opposite — the dashboard joins 7 tables to render one order card, and the reporting queries are lighting up the CPU at 85% every morning at 9am.

You've already tuned indexes. You've already added caching. The fundamental problem isn't hardware — the read model and the write model want **different shapes of the same data**, and you've been pretending they're the same thing for two years.

Here's the decision on the table:

A) Full CQRS — separate read/write models, project writes into a denormalized read store (ElasticSearch / a flat Postgres read DB), eventual consistency between them.

B) Add read replicas — point dashboards + reports at the replica, keep writes on the primary.

C) Keep one DB, one model — denormalize the write schema itself (flatten line_items into orders, duplicate customer data) so reads stop joining.

D) Keep the schema, add GraphQL + DataLoader — batch the N+1 reads at the query layer, leave the DB alone.

All four are real patterns you'll see in production. Three of them dodge the actual problem — and one of them is the senior engineer trap that looks correct for about 6 months until it doesn't.

Pick one — A, B, C, or D — and tell me why. Full breakdown in the comments.

If your team has argued about this exact tradeoff at 11pm before a release, share it with them. The debate sharpens the pattern.

Drop your answer 👇

#30DaysOfSystemDesign #Day9 #SystemDesign #SoftwareArchitecture

## Community discussion

Top comments from developers on daily.dev.

**@joudawad** · 39 upvotes

> **✅ Answer: A — Full CQRS**
>
>
> **Why A wins:**
>
> The pain isn't "reads are slow" — it's that the write side wants a normalized schema and the read side wants a denormalized one, and you're forcing them to share. No amount of hardware fixes a schema shape mismatch. Write side stays clean: orders, line_items, payments, all normalized, ACID, FK-enforced. Read side is a projection: a flat order_view table (or Elasticsearch index) where every order card renders from one row, zero joins. Projector keeps them in sync (outbox → Kafka → read-model updater, or CDC). You eat eventual consistency — the...

**@joudawad** · 12 upvotes

> **Why B is the trap (Read replicas):**
>
> B fixes read _load_. Not read _shape_. The 7-table join is still a 7-table join — it just runs on different hardware. You've moved the CPU bill, not removed it. Latency drops for 6 months while traffic grows, then you're back where you started with 3 replicas all running the same expensive joins. B is right when the joins are structurally fine but the primary is overwhelmed. Wrong when the joins themselves are the problem.

**@utkarshsharma** · 11 upvotes

> In the real world, B is usually the pragmatic first move, and A is the long-term structural answer. B buys time and A solves the architectural mismatch.

**@joudawad** · 9 upvotes

> **Why C is wrong (Denormalize the write model):**
>
> Every line-item change now rewrites the order row. Every address update cascades through every order ever placed. Write amplification compounds at 8K writes/min. Schema ossifies — adding a field to line_items means migrating millions of denormalized rows. Classic "avoid the architecture conversation" move. Buys a quarter, mortgages two.

**@joudawad** · 4 upvotes

> Also, it would mean a lot to me if you could support my content and stay in touch 🙏
>
> - YouTube: [https://www.youtube.com/@system-design-lab](https://www.youtube.com/@system-design-lab)
> - LinkedIn: [https://www.linkedin.com/in/joud-awad/](https://www.linkedin.com/in/joud-awad/)
> - Medium Blog: [https://joudwawad.medium.com/](https://joudwawad.medium.com/)
> - Substack: [https://joudawad.substack.com/](https://joudawad.substack.com/)

---

Tags: [#career](https://daily.dev/tags/career), [#backend](https://daily.dev/tags/backend), [#postgresql](https://daily.dev/tags/postgresql)

[View this post on daily.dev](https://daily.dev/posts/9-30-days-system-design-question-anwm4ygmc)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"DiscussionForumPosting","mainEntityOfPage":"https://daily.dev/posts/9-30-days-system-design-question-anwm4ygmc","headline":"9/30 Days System Design Question","text":"A system design challenge presents a Postgres monolith handling 8K writes/min and 40K reads/min where read and write models require fundamentally different data shapes. Four architectural options are evaluated: full CQRS with separate read/write stores, read replicas, denormalizing the write schema, or adding GraphQL with DataLoader. Readers are asked to pick the best approach and justify their reasoning, with the post hinting that one option is a senior engineer trap that works short-term but fails later.","url":"https://daily.dev/posts/9-30-days-system-design-question-anwm4ygmc","datePublished":"2026-05-14T18:26:41.775Z","dateModified":"2026-05-14T18:27:08.457Z","author":{"@type":"Person","name":"Joud Awad","url":"https://daily.dev/joudawad","image":"https://media.daily.dev/image/upload/s--dOB9RaXY--/f_auto/v1773320801/avatars/avatar_iaC4JsBU0lV8wBsc85fSh?_a=BAMAMiiu0","description":"Principal Solution Architecture ","worksFor":{"@type":"Organization","name":"Metalab","logo":"https://www.google.com/s2/favicons?domain=metalab.com&sz=128"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"EndorseAction"},"userInteractionCount":81900}},"image":"https://media.daily.dev/image/upload/s--pEZKFL4k--/f_auto/v1778783210/posts/AnwM4yGmC?_a=BAMAMiWQ0","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":400},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":68}],"comment":[{"@type":"Comment","text":"✅ Answer: A — Full CQRS\nWhy A wins:\nThe pain isn’t “reads are slow” — it’s that the write side wants a normalized schema and the read side wants a denormalized one, and you’re forcing them to share. No amount of hardware fixes a schema shape mismatch. Write side stays clean: orders, line_items, payments, all normalized, ACID, FK-enforced. Read side is a projection: a flat order_view table (or Elasticsearch index) where every order card renders from one row, zero joins. Projector keeps them in sync (outbox → Kafka → read-model updater, or CDC). You eat eventual consistency — the dashboard might lag by a few hundred ms. For 95% of reads (dashboards, reports, search), that’s invisible. For the 5% that needs strong consistency (user’s own order confirmation), read from the write side directly.","datePublished":"2026-05-14T18:27:31.558Z","dateModified":"2026-05-14T18:27:57.888Z","url":"https://daily.dev/posts/AnwM4yGmC#c-x8R45yQAk","author":{"@type":"Person","name":"Joud Awad","url":"https://daily.dev/joudawad","image":"https://media.daily.dev/image/upload/s--dOB9RaXY--/f_auto/v1773320801/avatars/avatar_iaC4JsBU0lV8wBsc85fSh?_a=BAMAMiiu0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":39}},{"@type":"Comment","text":"Why B is the trap (Read replicas):\nB fixes read load. Not read shape. The 7-table join is still a 7-table join — it just runs on different hardware. You’ve moved the CPU bill, not removed it. Latency drops for 6 months while traffic grows, then you’re back where you started with 3 replicas all running the same expensive joins. B is right when the joins are structurally fine but the primary is overwhelmed. Wrong when the joins themselves are the problem.","datePublished":"2026-05-14T18:28:04.767Z","url":"https://daily.dev/posts/AnwM4yGmC#c-JEyVEmWxl","author":{"@type":"Person","name":"Joud Awad","url":"https://daily.dev/joudawad","image":"https://media.daily.dev/image/upload/s--dOB9RaXY--/f_auto/v1773320801/avatars/avatar_iaC4JsBU0lV8wBsc85fSh?_a=BAMAMiiu0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":12}},{"@type":"Comment","text":"In the real world, B is usually the pragmatic first move, and A is the long-term structural answer. B buys time and A solves the architectural mismatch.","datePublished":"2026-05-14T21:04:43.700Z","dateModified":"2026-05-14T21:05:16.468Z","url":"https://daily.dev/posts/AnwM4yGmC#c-dZaFiyumN","author":{"@type":"Person","name":"Utkarsh Sharma","url":"https://daily.dev/utkarshsharma","image":"https://lh3.googleusercontent.com/a/ACg8ocLWTIlLlLobCvKgMgUdmyKpXQ8imq6sni-370_MhAxy=s96-c"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":11}},{"@type":"Comment","text":"Why C is wrong (Denormalize the write model):\nEvery line-item change now rewrites the order row. Every address update cascades through every order ever placed. Write amplification compounds at 8K writes/min. Schema ossifies — adding a field to line_items means migrating millions of denormalized rows. Classic “avoid the architecture conversation” move. Buys a quarter, mortgages two.","datePublished":"2026-05-14T18:28:09.644Z","url":"https://daily.dev/posts/AnwM4yGmC#c-y7XLm3LY6","author":{"@type":"Person","name":"Joud Awad","url":"https://daily.dev/joudawad","image":"https://media.daily.dev/image/upload/s--dOB9RaXY--/f_auto/v1773320801/avatars/avatar_iaC4JsBU0lV8wBsc85fSh?_a=BAMAMiiu0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":9}},{"@type":"Comment","text":"Also, it would mean a lot to me if you could support my content and stay in touch 🙏\n\nYouTube: https://www.youtube.com/@system-design-lab\nLinkedIn: https://www.linkedin.com/in/joud-awad/\nMedium Blog: https://joudwawad.medium.com/\nSubstack: https://joudawad.substack.com/","datePublished":"2026-05-14T18:59:46.335Z","dateModified":"2026-05-15T16:18:54.377Z","url":"https://daily.dev/posts/AnwM4yGmC#c-fx7mzEb1c","author":{"@type":"Person","name":"Joud Awad","url":"https://daily.dev/joudawad","image":"https://media.daily.dev/image/upload/s--dOB9RaXY--/f_auto/v1773320801/avatars/avatar_iaC4JsBU0lV8wBsc85fSh?_a=BAMAMiiu0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":4}}],"isPartOf":{"@type":"WebPage","url":"https://daily.dev/sources/iac4jsbu0lv8wbsc85fsh","name":"Joud Awad"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Joud Awad","item":"https://daily.dev/sources/iac4jsbu0lv8wbsc85fsh"},{"@type":"ListItem","position":3,"name":"9/30 Days System Design Question"}]}
```

