Two sides that want opposite things
Most applications treat reads and writes as mirror images. One set of tables, a mapping layer in front, the same object flowing both directions.
The two sides actually want opposite things. That observation is what this pattern is built on.
Your write side wants normalised data, validation and rules: an order cannot ship before payment clears. Your read side wants denormalised answers shaped exactly like the screen: a dashboard with order counts, revenue and top products, in one fetch.
Split them and a command like place this order goes through the write model, which enforces the rules and saves the change. The read side keeps separate views, precomputed and updated as changes flow through, so your dashboard query becomes a single-row lookup instead of a nine-table join.
Scale the two independently while you are at it, which matters because most systems read ten to a hundred times more than they write.
The lag you accept
Pay for it with lag, because your read model trails your write model. Updates propagate in the background, typically within milliseconds to seconds, and your interface has to live inside that window.
Handle the obvious case deliberately: someone submits an order and the list they immediately load may not show it yet. Return the new state in the response to the command, or read that one screen from the write side.
Take one warning before going further. None of this requires event sourcing, a message bus, or separate databases.
Build the lightest version first: two code paths over one database, commands through your domain model and queries through hand-written SQL against read-shaped views. Plenty of teams stop there and get most of the benefit.
Worked example
Tobias runs the backend for a marketplace seller dashboard. The dashboard query joins nine tables (orders, items, refunds, payouts, and more) and takes 2.8 seconds for large sellers; one seller with 40,000 orders times out entirely. The write path is fine, so he leaves it alone and adds a read model: a seller_dashboard table with one row per seller holding precomputed counts and revenue, updated by a worker that consumes order and refund changes. Dashboard load drops to 20 ms for every seller, including the 40,000-order one. Lag between a new order and the dashboard reflecting it averages 800 ms, which nobody notices. Total new infrastructure: one table and one worker, no event sourcing, no new database, same Postgres.