<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Event-Sourcing on IT Comparison</title><link>https://comparison.metacog.co.kr/tags/event-sourcing/</link><description>Recent content in Event-Sourcing on IT Comparison</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Tue, 04 Aug 2026 05:10:16 +0900</lastBuildDate><atom:link href="https://comparison.metacog.co.kr/tags/event-sourcing/index.xml" rel="self" type="application/rss+xml"/><item><title>Event Sourcing vs State-Based Persistence: Storing Changes vs Storing Current State</title><link>https://comparison.metacog.co.kr/posts/2026-08-04-event-sourcing-vs-state-based-persistence-storing-changes-vs/</link><pubDate>Tue, 04 Aug 2026 05:10:16 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-04-event-sourcing-vs-state-based-persistence-storing-changes-vs/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Event sourcing persists every change to an entity as an immutable, ordered &lt;strong class="kw"&gt;event log&lt;/strong&gt;, deriving current state by replaying that history. State-based persistence instead stores and overwrites a single &lt;strong class="kw"&gt;current record&lt;/strong&gt;, discarding prior values on each update. The choice affects auditability, storage growth, and how much replay/projection machinery you need to build.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;line x1="320" y1="20" x2="320" y2="340" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="4,4"/&gt;&lt;text x="160" y="32" text-anchor="middle" style="fill:var(--primary)" font-size="16" font-weight="bold"&gt;Event Sourcing&lt;/text&gt;&lt;rect x="60" y="52" width="200" height="32" rx="3" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="72" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;AccountOpened&lt;/text&gt;&lt;rect x="60" y="90" width="200" height="32" rx="3" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="110" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Deposited $100&lt;/text&gt;&lt;rect x="60" y="128" width="200" height="32" rx="3" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="148" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Withdrew $30&lt;/text&gt;&lt;rect x="60" y="166" width="200" height="32" rx="3" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="186" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;Deposited $50&lt;/text&gt;&lt;line x1="160" y1="198" x2="160" y2="238" style="stroke:var(--compare-a)" stroke-width="1.5" marker-end="url(#arrowA)"/&gt;&lt;text x="178" y="222" style="fill:var(--secondary)" font-size="10"&gt;replay&lt;/text&gt;&lt;rect x="85" y="246" width="150" height="34" rx="3" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="2"/&gt;&lt;text x="160" y="268" text-anchor="middle" style="fill:var(--content)" font-size="12" font-weight="bold"&gt;Balance: $120&lt;/text&gt;&lt;text x="160" y="304" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;Full history preserved&lt;/text&gt;&lt;text x="480" y="32" text-anchor="middle" style="fill:var(--primary)" font-size="16" font-weight="bold"&gt;State-Based Persistence&lt;/text&gt;&lt;rect x="400" y="56" width="160" height="32" rx="3" style="fill:none;stroke:var(--border)" stroke-width="1.5" stroke-dasharray="3,3"/&gt;&lt;text x="480" y="76" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;Balance: $0&lt;/text&gt;&lt;line x1="480" y1="88" x2="480" y2="104" style="stroke:var(--border)" stroke-width="1.5" marker-end="url(#arrowB)"/&gt;&lt;rect x="400" y="106" width="160" height="32" rx="3" style="fill:none;stroke:var(--border)" stroke-width="1.5" stroke-dasharray="3,3"/&gt;&lt;text x="480" y="126" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;Balance: $100&lt;/text&gt;&lt;line x1="480" y1="138" x2="480" y2="154" style="stroke:var(--border)" stroke-width="1.5" marker-end="url(#arrowB)"/&gt;&lt;rect x="400" y="156" width="160" height="32" rx="3" style="fill:none;stroke:var(--border)" stroke-width="1.5" stroke-dasharray="3,3"/&gt;&lt;text x="480" y="176" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;Balance: $70&lt;/text&gt;&lt;line x1="480" y1="188" x2="480" y2="210" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrowB)"/&gt;&lt;text x="500" y="202" style="fill:var(--secondary)" font-size="10"&gt;overwrite&lt;/text&gt;&lt;rect x="405" y="216" width="150" height="34" rx="3" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="2"/&gt;&lt;text x="480" y="238" text-anchor="middle" style="fill:var(--content)" font-size="12" font-weight="bold"&gt;Balance: $120&lt;/text&gt;&lt;text x="480" y="304" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;Only latest state kept&lt;/text&gt;&lt;defs&gt;&lt;marker id="arrowA" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto"&gt;&lt;path d="M0,0 L8,4 L0,8 Z" style="fill:var(--compare-a)"/&gt;&lt;/marker&gt;&lt;marker id="arrowB" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto"&gt;&lt;path d="M0,0 L8,4 L0,8 Z" style="fill:var(--border)"/&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Event Sourcing&lt;/th&gt;
&lt;th&gt;State-Based Persistence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Write operation&lt;/td&gt;
&lt;td&gt;Appends a new immutable event to the log; nothing is ever modified in place&lt;/td&gt;
&lt;td&gt;Updates or overwrites the existing row/record with new values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data representation&lt;/td&gt;
&lt;td&gt;Sequence of domain events describing what happened&lt;/td&gt;
&lt;td&gt;Single current snapshot of the entity&amp;rsquo;s fields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reading current state&lt;/td&gt;
&lt;td&gt;Replay events from the start (or from a snapshot) to derive current state&lt;/td&gt;
&lt;td&gt;Direct read of the stored row, no reconstruction needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrency conflicts&lt;/td&gt;
&lt;td&gt;Detected by checking the expected event stream version before appending&lt;/td&gt;
&lt;td&gt;Detected via optimistic locking (row version/timestamp) or DB-level locks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Historical/audit trail&lt;/td&gt;
&lt;td&gt;Native and complete — every past state is reconstructable&lt;/td&gt;
&lt;td&gt;Not retained by default; requires a separate audit log or triggers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schema evolution&lt;/td&gt;
&lt;td&gt;Old event versions must be upcast or handled explicitly by consumers&lt;/td&gt;
&lt;td&gt;Existing rows are migrated or altered directly to the new shape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage growth&lt;/td&gt;
&lt;td&gt;Grows unbounded with every change; needs snapshotting/compaction to stay fast&lt;/td&gt;
&lt;td&gt;Stays roughly proportional to the number of entities, not their history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query complexity&lt;/td&gt;
&lt;td&gt;Ad-hoc queries need dedicated projections/read models built from the events&lt;/td&gt;
&lt;td&gt;Supports direct ad-hoc SQL queries against the current data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Event sourcing stores an append-only &lt;strong class="kw"&gt;event log&lt;/strong&gt;; state-based persistence stores only the &lt;strong class="kw"&gt;current row&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Rebuilding state requires &lt;strong class="kw"&gt;replay&lt;/strong&gt; in event sourcing, versus a simple read in state-based systems&lt;/li&gt;
&lt;li&gt;Event sourcing gives a native &lt;strong class="kw"&gt;audit trail&lt;/strong&gt;; state-based needs bolt-on logging to recover history&lt;/li&gt;
&lt;li&gt;Concurrency is resolved via &lt;strong class="kw"&gt;event versioning&lt;/strong&gt; instead of row-level locking&lt;/li&gt;
&lt;li&gt;Storage grows unbounded without &lt;strong class="kw"&gt;snapshots&lt;/strong&gt; in event sourcing, while state-based storage stays compact&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Event Sourcing&lt;/strong&gt;&lt;/p&gt;</description></item></channel></rss>