<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[The Cloud Playbook]]></title><description><![CDATA[Playbooks for engineering leaders running multitenant SaaS on AWS who choose predictability over speed: boringly reliable services, controlled cloud spend, and audit-ready compliance.]]></description><link>https://www.thecloudplaybook.com</link><image><url>https://substackcdn.com/image/fetch/$s_!7MI5!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b1ca555-b578-4ae3-8dda-a03cbc6b1d18_500x500.png</url><title>The Cloud Playbook</title><link>https://www.thecloudplaybook.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 28 Oct 2026 00:28:18 GMT</lastBuildDate><atom:link href="https://www.thecloudplaybook.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Amrut Patil]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[thecloudplaybook@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[thecloudplaybook@substack.com]]></itunes:email><itunes:name><![CDATA[Amrut Patil]]></itunes:name></itunes:owner><itunes:author><![CDATA[Amrut Patil]]></itunes:author><googleplay:owner><![CDATA[thecloudplaybook@substack.com]]></googleplay:owner><googleplay:email><![CDATA[thecloudplaybook@substack.com]]></googleplay:email><googleplay:author><![CDATA[Amrut Patil]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[TCP #147: The Streaming Pipeline That Does Not Page You]]></title><description><![CDATA[Shard capacity, Firehose buffering, replay design, and the alarms that actually justify waking someone.]]></description><link>https://www.thecloudplaybook.com/p/kinesis-s3-athena-pipeline</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/kinesis-s3-athena-pipeline</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 25 Oct 2026 14:30:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!PPA7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The previous issue showed that streaming incurs operational costs.</p><p>Here is how to build a Kinesis-to-S3-to-Athena pipeline so owning it remains sustainable.</p><p>The goal is not maximum throughput or minimum theoretical latency.</p><p>AWS services can handle those requirements.</p><p>The goal is fewer unnecessary pages, safe recovery when records fail, and landed data that Athena can query efficiently.</p><p>A streaming pipeline is successful when it delivers fresh data without turning two engineers into permanent babysitters.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PPA7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PPA7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!PPA7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!PPA7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!PPA7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PPA7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1953046,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/214374284?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PPA7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!PPA7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!PPA7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!PPA7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb727c4a0-4167-4db3-8f7a-8fb72e5a8b75_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Why Operational Load Decides Whether Streaming Was Worth It</h2><p>The business case for streaming is made on latency.</p><p>The real cost is paid in on-call hours.</p><p>A pipeline that pages twice per month consumes more than its infrastructure budget. It interrupts engineers, reduces roadmap capacity, and creates a reliability tax that rarely appears in the original architecture decision.</p><p>Track these metrics:</p><ul><li><p>Pages per month</p></li><li><p>Ratio of pages to real incidents</p></li><li><p>Mean time to recovery</p></li><li><p>Dead-letter record rate</p></li><li><p>Average S3 object size</p></li><li><p>Producer throttling events</p></li></ul><p>The goal is not zero alerts.</p><p>The goal is for every page to represent a condition requiring immediate human action.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>How Streaming Pipelines Create Unnecessary Pages</h2><h3>Self-resolving consumer lag</h3><p>A traffic burst increases Kinesis consumer lag. <code>IteratorAgeMilliseconds</code> rises, then falls once the consumer catches up.</p><p>If every temporary spike pages someone, the alert is measuring movement rather than danger.</p><p>Use warning and page thresholds. Notify the team when lag increases but the consumer is recovering. Page when lag is sustained, recovery has stalled, or the stream is approaching a retention boundary.</p><h3>Small files in Amazon S3</h3><p>Firehose delivers objects when the configured size or time condition is met first.</p><p>With dynamic partitioning, buffering occurs separately for active partitions. Low-volume partitions may flush based on time before reaching the desired object size.</p><p>A stream can appear healthy while creating thousands of small S3 objects.</p><p>Nothing fails immediately.</p><p>Athena simply becomes slower and more expensive over time.</p><h3>Untested dead-letter handling</h3><p>A dead-letter prefix is not a recovery system.</p><p>It is only a location where failed records wait.</p><p>If replay has not been implemented and tested, the first malformed record becomes both a production incident and an engineering project.</p><p>Build replay before production.</p><h2>The Three Decisions That Set Operational Load</h2><h3>1. Kinesis capacity: on-demand or provisioned?</h3><p>On-demand reduces shard-management work and usually fits spiky traffic or small teams better.</p><p>Provisioned capacity can be more economical for high, predictable throughput, but the team owns capacity monitoring, scaling, and resharding decisions.</p><p>The question is not which mode is cheaper in isolation.</p><p>The question is whether someone owns capacity review and whether the traffic pattern justifies the operational work.</p><p>A provisioned stream nobody resizes is not optimized.</p><p>It is neglected.</p><p>Monitor producer and consumer throttling separately. Producer throttling is especially important because it can prevent records from entering the stream in the first place.</p><h3>2. Firehose buffering: freshness or object size?</h3><p>Firehose delivers when the size or time condition is met first. The configured values are buffering hints, not guarantees.</p><p>Set the largest buffer size and longest interval the actual freshness requirement allows.</p><p>Do not assume a 128 MB setting means every delivered object will be 128 MB. Dynamic partitioning creates separate buffers per active partition, and low-volume partitions may flush on time before reaching the size target.</p><p>High-cardinality partition keys can create too many active buffers and produce small objects.</p><p>Choose the partition key for both query behavior and delivery behavior.</p><h3>3. Error handling: drop, block, or replay?</h3><p>Dropping malformed records keeps the pipeline moving but silently loses data.</p><p>Blocking preserves data but allows one bad record to stop the stream.</p><p>A dead-letter path with tested replay is the correct default.</p><p>The replay process must define:</p><ul><li><p>Where failed records are stored</p></li><li><p>How the original event ID is preserved</p></li><li><p>How records are reprocessed</p></li><li><p>How duplicates are prevented</p></li><li><p>How successful replay is verified</p></li><li><p>When a failed record is permanently quarantined</p></li></ul><p>If replay cannot establish whether a record landed once, the pipeline is not recoverable.</p><h2>Building the Pipeline</h2><h3>1. Size capacity from peak traffic</h3><p>Estimate capacity from measured peak throughput, not average throughput.</p><p>Averages hide the burst that causes throttling.</p><p>Use historical peak traffic, add operating margin, and document the scaling trigger. For provisioned streams, define who reviews capacity and how often.</p><p>For on-demand streams, still monitor throughput, throttling, iterator age, and cost.</p><p>Removing shard management does not remove the need for capacity visibility.</p><h3>2. Choose the partition key from query behavior</h3><p>Use dynamic partitioning based on a field analysts actually filter on.</p><p>A useful key usually has:</p><ul><li><p>Predictable values</p></li><li><p>Manageable cardinality</p></li><li><p>Sufficient volume per partition</p></li><li><p>A direct relationship to common Athena predicates</p></li></ul><p>Do not partition by a field simply because it appears in every event.</p><p>A high-cardinality key can create too many active Firehose partitions and small S3 objects. A low-cardinality key may produce efficient objects but weak query pruning.</p><p>The correct key balances query behavior and delivery behavior.</p><h3>3. Define a strict S3 layout</h3><p>Use a predictable prefix such as:</p><pre><code><code>dataset/event_date=YYYY-MM-DD/hour=HH/
</code></code></pre><p>Keep the layout stable so Athena partition projection can calculate locations without requiring a crawler for every delivery.</p><p>Decide the partition convention before the stream ships. Repartitioning later means migrating data, updating the table, and validating every consumer.</p><h3>4. Configure buffering from the real latency requirement</h3><p>Start with the longest interval the business can tolerate.</p><p>Then measure actual object sizes and delivery freshness.</p><p>Do not assume one global buffer setting produces one global object size. Dynamic partitioning creates separate buffers per active partition, and low-volume partitions may flush on time rather than size.</p><p>If files are consistently too small:</p><ul><li><p>Reduce partition-key cardinality</p></li><li><p>Increase the interval if permitted</p></li><li><p>Consolidate low-volume partitions</p></li><li><p>Add a compaction process</p></li><li><p>Reconsider whether the stream should partition at ingestion</p></li></ul><h3>5. Build replay before production</h3><p>Send deliberately malformed records through the pipeline before launch.</p><p>Verify that they:</p><ol><li><p>Reach the dead-letter location.</p></li><li><p>Retain enough metadata to identify the original event.</p></li><li><p>Can be replayed without manual reconstruction.</p></li><li><p>Land in the intended S3 prefix.</p></li><li><p>Do not create uncontrolled duplicates.</p></li><li><p>Remove or mark only after successful verification.</p></li></ol><p>An untested replay path is not error handling.</p><p>It is storage with optimistic branding.</p><h3>6. Use tiered iterator-age alarms</h3><p>Use a warning notification for temporary lag and a page for sustained lag that threatens retention or indicates the consumer cannot recover.</p><p>The exact thresholds depend on stream retention, traffic, and recovery time.</p><p>Do not copy universal thresholds without measuring your pipeline.</p><p>The page threshold should answer:</p><blockquote><p><em>If nobody acts now, is data loss or an unrecoverable freshness breach likely?</em></p></blockquote><p>If the answer is no, notify.</p><p>Do not page.</p><h3>7. Page on data-loss conditions</h3><p>Producer throttling and failed writes deserve urgent treatment because they can prevent records from entering the stream.</p><p>Monitor producer success rates, write throttling, and failed producer operations.</p><p>Consumer lag is not automatically data loss.</p><p>Producer rejection can be.</p><h3>8. Monitor object-size degradation</h3><p>Track average and p95 object size in the S3 landing prefix.</p><p>Alert when object size falls below the threshold that makes Athena performance or request overhead unacceptable for your workload.</p><p>Do not treat 64 MB or 128 MB as universal laws. They are operating thresholds to test against query performance, partition count, and delivery latency.</p><h3>9. Alert on dead-letter growth</h3><p>One malformed record may be normal.</p><p>A rising dead-letter rate usually indicates an upstream schema change, transformation bug, or invalid payload pattern.</p><p>Monitor:</p><ul><li><p>Dead-letter records per minute</p></li><li><p>Dead-letter rate as a percentage of total records</p></li><li><p>Change from the trailing baseline</p></li><li><p>Age of the oldest unreplayed record</p></li></ul><p>The important signal is accumulation.</p><h3>10. Put the action in the alarm</h3><p>Every alarm should link to a runbook containing:</p><ul><li><p>What the alarm means</p></li><li><p>The first diagnostic command</p></li><li><p>Two likely causes</p></li><li><p>Whether to page or notify</p></li><li><p>Immediate remediation</p></li><li><p>Escalation owner</p></li><li><p>Recovery verification</p></li></ul><p>An alarm without an action is a notification that forces a tired engineer to invent a procedure at 3 AM.</p><h2>The Streaming Pipeline Alarm Matrix</h2><p>Before production, review every alarm with the engineer who carries the pager.</p><p>Page only when immediate human action is required to prevent data loss, an SLA breach, or an unrecoverable failure.</p><h3><strong>Temporary iterator-age increase</strong></h3><p><strong><span>Severity:</span></strong> Notify</p><p><strong><span>Action:</span></strong> Monitor recovery.</p><p>If the consumer is catching up and the stream remains within its retention window, notify the team and observe recovery.</p><h3><strong>Sustained iterator age approaching retention risk</strong></h3><p><strong><span>Severity:</span></strong> Page</p><p><strong><span>Action:</span></strong> Investigate consumer capacity immediately.</p><p>Check consumer throughput, processing errors, throttling, and recent traffic changes.</p><h3><strong>Producer throttling or failed writes</strong></h3><p><strong><span>Severity:</span></strong> Page</p><p><strong><span>Action:</span></strong> Protect against data loss.</p><p>Check stream capacity, producer error rates, retry behavior, and recent traffic volume.</p><h3><strong>Dead-letter rate increase</strong></h3><p><strong><span>Severity:</span></strong> Notify or page based on loss risk</p><p><strong><span>Action:</span></strong> Investigate the schema or transformation failure.</p><p>Notify when records are safely retained, and replay remains within its recovery objective.</p><p>Page when the backlog is growing toward an SLA breach or records may be lost.</p><h3><strong>Object-size degradation</strong></h3><p><strong><span>Severity:</span></strong> Notify</p><p><strong><span>Action:</span></strong> Correct buffering or partition strategy.</p><p>Review Firehose buffering, dynamic partitioning, traffic distribution, and partition-key cardinality.</p><h3><strong>Aging replay backlog</strong></h3><p><strong><span>Severity:</span></strong> Page if the recovery SLA is threatened</p><p><strong><span>Action:</span></strong> Execute the replay procedure.</p><p>Page when unreplayed records approach the maximum recovery window, the backlog grows faster than it can be processed, or replay stops making progress.</p><p>If the person carrying the pager does not agree that an alarm deserves a page, the alarm design is unfinished.</p><p>A page is a request for immediate action.</p><p>Treat it like one.</p><h2>What to Measure Monthly</h2><p>Track:</p><ul><li><p>Pages per month</p></li><li><p>Ratio of pages to real incidents</p></li><li><p>Mean time from alert to confirmed data state</p></li><li><p>Average and p95 landed S3 object size</p></li><li><p>Dead-letter rate</p></li><li><p>Oldest unreplayed record</p></li><li><p>Producer throttle events</p></li><li><p>Consumer iterator age</p></li><li><p>Active dynamic partitions</p></li><li><p>Athena bytes scanned for landed tables</p></li></ul><p>Review alarm thresholds quarterly with on-call engineers.</p><p>Review provisioned capacity monthly.</p><p>Review object sizes and Athena scan behavior monthly because delivery configuration and query usage change independently.</p><h2>The Measure of a Good Streaming Pipeline Is Silence</h2><p>A well-built Kinesis-to-S3-to-Athena pipeline is one your team does not have to watch constantly.</p><p>It lands queryable data, keeps partition behavior predictable, sends malformed records to a tested replay path, and pages only when a human must act.</p><p>That is the evidence that the streaming decision was correct.</p><p>Not the architecture diagram.</p><p>Not the fact that data arrives in seconds.</p><p>The evidence is the number of unnecessary pages.</p><p>Take your most page-prone pipeline and complete the alarm matrix against its current configuration.</p><p>Where the matrix and the live system disagree is where your unnecessary pages come from.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #146: Most Streaming Pipelines Answer a Question Nobody Asked]]></title><description><![CDATA[Five questions and a simple break-even test for choosing streaming or micro-batch per pipeline.]]></description><link>https://www.thecloudplaybook.com/p/tcp-146-most-streaming-pipelines</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/tcp-146-most-streaming-pipelines</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 18 Oct 2026 14:35:38 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!96zk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Streaming gets chosen for the wrong reason more often than almost any other data architecture decision.</p><p>The reason is rarely a documented latency requirement.</p><p>It is that streaming sounds modern, while proposing a batch pipeline in a design review can sound like settling.</p><p>So the team builds streaming:</p><ul><li><p>Kinesis</p></li><li><p>A consumer application</p></li><li><p>Checkpointing</p></li><li><p>A dead-letter path</p></li><li><p>Monitoring and alerting</p></li><li><p>An on-call rotation</p></li></ul><p>The pipeline delivers data four seconds after the event.</p><p>The dashboard is reviewed once each morning.</p><p>The cost isn't just the infrastructure bill. It is the operational surface: an always-running system with failure modes that can page a human, built to satisfy a freshness requirement nobody properly defined.</p><p><strong><span>Real-time is a requirement, not a default.</span></strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!96zk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!96zk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!96zk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!96zk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!96zk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!96zk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2071693,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/214373857?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!96zk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!96zk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!96zk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!96zk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8763f66c-eb67-40ba-b2ab-e9196adc68e0_1536x1024.png 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Why Streaming Costs More Than Its Infrastructure Bill</h2><p>The infrastructure cost is only the visible part.</p><p>The larger cost is operational.</p><p>A streaming pipeline is always running. That means it can always fail. It requires monitoring, alerting, replay procedures, capacity planning, and engineers who understand the system well enough to respond under pressure.</p><p>A micro-batch pipeline that runs every fifteen minutes has a different failure profile. It processes data in bounded windows. It can retry within the next window. A failure may delay freshness, but it does not necessarily require immediate human intervention.</p><p>Streaming also introduces more concepts for the team to own:</p><ul><li><p>Backpressure</p></li><li><p>Out-of-order events</p></li><li><p>Checkpoint management</p></li><li><p>Replay behavior</p></li><li><p>Watermarks</p></li><li><p>Duplicate delivery</p></li><li><p>Consumer lag</p></li><li><p>Partition or shard capacity</p></li></ul><p>These are not theoretical concerns. They become operational responsibilities.</p><p>There is also a concentration risk. Many organizations have only one or two engineers who deeply understand the streaming stack. Every change then depends on the same people.</p><p>That is not just a staffing inconvenience.</p><p>It is a reliability constraint.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Why Freshness Requirements Become Inflated</h2><p>Most freshness requirements are inherited rather than derived.</p><p>Someone asks a stakeholder how fresh the data should be. With no cost or operational context, the answer is often &#8220;real time.&#8221;</p><p>That answer becomes a requirement.</p><p>Eighteen months later, the team is maintaining a streaming pipeline because of one unpriced conversation.</p><p>Ask a better question:</p><blockquote><p><em>What decision does this data support, and how quickly after the event must that decision happen?</em></p></blockquote><p>Consider the difference:</p><ul><li><p>A fraud system may need to react within seconds.</p></li><li><p>An operational dashboard may need updates every fifteen minutes.</p></li><li><p>A daily revenue report may only need correct data by 8 AM.</p></li><li><p>A weekly cohort analysis may only need data by Monday.</p></li></ul><p>These are different business requirements.</p><p>They should produce different architectures.</p><p>The other source of inflation is anticipated future need.</p><p>Teams build streaming because they might need real-time later. Then they pay the operational cost for years while the requirement never arrives.</p><p>When the requirement finally does arrive, it usually applies to one pipeline, not the entire platform.</p><h2>The Five Questions to Ask Per Pipeline</h2><h3>1. What decision does this data drive?</h3><p>Do not ask how fresh the data should be.</p><p>Ask what someone or something does with it.</p><p>If a human reviews the data during business hours, the actual requirement may be measured in minutes or hours.</p><p>If an automated system must react immediately, streaming becomes more defensible.</p><p>Architecture should follow the decision, not the preference of the person writing the requirements document.</p><h3>2. Is there an automated action triggered by the data?</h3><p>Automated response is the strongest reason to choose streaming.</p><p>Examples include:</p><ul><li><p>Blocking a suspicious transaction</p></li><li><p>Triggering a safety response</p></li><li><p>Updating a user-facing experience immediately</p></li><li><p>Routing an operational event</p></li><li><p>Detecting a system failure within seconds</p></li></ul><p>If nothing happens automatically and the data is only reviewed later, micro-batch may provide the required outcome with less operational burden.</p><h3>3. What is the concrete cost of fifteen minutes of staleness?</h3><p>State the consequence.</p><p>Does fifteen-minute-old data:</p><ul><li><p>Lose revenue?</p></li><li><p>Increase fraud exposure?</p></li><li><p>Delay an operational response?</p></li><li><p>Violate a contractual requirement?</p></li><li><p>Create a safety issue?</p></li><li><p>Prevent a customer from completing an action?</p></li></ul><p>If nobody can name the consequence, there may not be a genuine latency requirement.</p><p>Do not buy a permanently running system to avoid an inconvenience that has never been priced.</p><h3>4. Does the volume make batch impractical?</h3><p>Latency is not the only reason streaming may be necessary.</p><p>Sustained event volume can make batch processing impractical if each batch must process more data than arrived during the previous window.</p><p>You may be approaching a simple constraint:</p><blockquote><p><em>Processing time is greater than the batch interval.</em></p></blockquote><p>If a fifteen-minute batch takes twenty minutes to process, the pipeline cannot keep up. The backlog compounds.</p><p>That is a legitimate reason to consider streaming, independent of whether anyone needs sub-minute freshness.</p><p>Measure:</p><ul><li><p>Events per second</p></li><li><p>Average and peak volume</p></li><li><p>Batch processing duration</p></li><li><p>Batch interval</p></li><li><p>Backlog growth</p></li><li><p>Recovery time after failure</p></li></ul><p>Do not confuse a temporary implementation problem with a permanent streaming requirement. A faster batch job, better partitioning, or a larger processing window may solve the issue.</p><h3>5. Does the team have on-call capacity?</h3><p>Streaming belongs in the operating model, not only in the architecture diagram.</p><p>Ask:</p><ul><li><p>Who owns the pipeline at 2 AM?</p></li><li><p>Who responds to consumer lag?</p></li><li><p>Who handles duplicate or out-of-order events?</p></li><li><p>Who replays a failed time range?</p></li><li><p>Who responds when capacity is exhausted?</p></li><li><p>Who maintains the dead-letter path?</p></li></ul><p>If the team is already stretched, adding another always-on system creates reliability debt.</p><p>A streaming design that nobody can operate is not production-ready, regardless of how elegant the topology looks.</p><h2>The Break-Even Test</h2><p>The basic latency test is simple:</p><blockquote><p><em>If the required decision latency is comfortably longer than the batch interval, micro-batch is usually sufficient.</em></p></blockquote><p>For example:</p><ul><li><p>Required decision latency: 45 minutes</p></li><li><p>Proposed micro-batch interval: 15 minutes</p></li><li><p>Processing time: 4 minutes</p></li></ul><p>That pipeline has margin. Streaming is difficult to justify unless another factor, such as sustained volume or automated action, changes the economics.</p><p>Now consider:</p><ul><li><p>Required decision latency: 30 seconds</p></li><li><p>Proposed micro-batch interval: 15 minutes</p></li></ul><p>Micro-batch cannot satisfy the requirement. Streaming earns its additional complexity.</p><p>Also calculate whether batch can keep up:</p><pre><code><code>Batch processing time &lt; Batch interval
</code></code></pre><p>If processing time consistently approaches or exceeds the interval, the batch design is under pressure.</p><p>A pipeline may need streaming when:</p><ul><li><p>The required latency is below the practical batch interval</p></li><li><p>Automated action must happen quickly</p></li><li><p>Sustained volume causes batch backlog</p></li><li><p>The business cost of delay exceeds the operational cost of streaming</p></li></ul><p>Otherwise, micro-batch should be the default you test first.</p><h2>What Choosing Honestly Returns</h2><p>Teams that evaluate pipelines individually usually end up with a small number of streaming systems where the requirement is real and micro-batch everywhere else.</p><p>The first return is lower on-call load.</p><p>Fewer always-on systems mean fewer pages and fewer specialized systems competing for the same engineers.</p><p>The second return is faster delivery. Micro-batch pipelines are usually quicker to launch because the operational hardening burden is smaller.</p><p>The third return is better attention allocation. The streaming pipelines that remain receive the expertise they need instead of competing with six unnecessary streaming systems for the same two engineers.</p><p>There is a legitimate case for streaming.</p><p>When automated action, genuine sub-minute decisions, or sustained volume make batch the constraint, build streaming properly.</p><p>Do not stretch batch beyond what it can handle.</p><p>But do not build streaming to avoid looking old-fashioned in a design review.</p><h2>The Decision Tree</h2><p>Use this sequence for every pipeline:</p><ol><li><p><strong><span>What decision does the data support?</span></strong></p></li><li><p><strong><span>How quickly must that decision happen?</span></strong></p></li><li><p><strong><span>Is there an automated action?</span></strong></p></li><li><p><strong><span>Can batch process the volume within the required window?</span></strong></p></li><li><p><strong><span>Can the team operate another always-on system?</span></strong></p></li></ol><p>Then classify the result:</p><ul><li><p><strong><span>Micro-batch:</span></strong> Human-reviewed data, flexible decision timing, manageable volume, limited on-call capacity.</p></li><li><p><strong><span>Streaming:</span></strong> Automated response, genuine sub-minute requirement, or batch throughput constraint.</p></li><li><p><strong><span>Re-evaluate:</span></strong> Conflicting answers, undocumented requirements, or an architecture based primarily on anticipated future demand.</p></li></ul><p>Write down the decision and the reason.</p><p>Revisit it when volume, consumers, latency requirements, or operating capacity changes.</p><p>The architecture should evolve when constraints change.</p><h2>The Payoff Is Fewer Systems That Matter</h2><p>Streaming is not bad.</p><p>Unnecessary streaming is expensive.</p><p>A micro-batch pipeline that meets the business requirement is often the better system because it is easier to build, operate, explain, and recover.</p><p>A streaming pipeline that satisfies a real automated or latency-sensitive requirement is worth the complexity.</p><p>The mistake is treating one pattern as the default for every workload.</p><p>Use the smallest architecture that satisfies the actual decision latency and volume constraint.</p><p>That is not conservatism.</p><p>That is engineering.</p><p>Before approving the next streaming pipeline, make the requestor answer five questions:</p><ul><li><p>What decision does this data drive?</p></li><li><p>How quickly must the decision happen?</p></li><li><p>What is the cost of fifteen minutes of staleness?</p></li><li><p>Can batch keep up with the volume?</p></li><li><p>Who owns the system when it fails?</p></li></ul><p>If the answers are vague, build the simpler pipeline first.</p><p>The goal is not to make data arrive as quickly as possible.</p><p>The goal is to make the right decision at the right cost without creating an on-call rotation nobody needs.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #145: Athena Optimization, In the Order That Pays]]></title><description><![CDATA[Partition projection, Parquet economics, and the predicate mistakes that make partitioned tables scan in full.]]></description><link>https://www.thecloudplaybook.com/p/optimizing-athena-partitioning-parquet</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/optimizing-athena-partitioning-parquet</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 11 Oct 2026 14:30:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!8w5q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The previous issue showed you how to find the tables driving your Athena scan volume.</p><p>This is the system for fixing them in the order that creates the highest return per hour of engineering time.</p><p>The order matters.</p><p>Partitioning, partition projection, file format, and query predicates all interact. Make the wrong change first<strong>,</strong> and you may have to redo the work.</p><p>The optimization sequence is:</p><ol><li><p>Find the dominant query predicates.</p></li><li><p>Verify the partition key matches them.</p></li><li><p>Confirm partition pruning is actually occurring.</p></li><li><p>Move to partition projection where the layout supports it.</p></li><li><p>Convert qualifying tables to Parquet.</p></li><li><p>Measure the result against the original baseline.</p></li></ol><p>Do not start by converting every table to Parquet.</p><p>Start with the tables that cost you the most.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8w5q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8w5q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!8w5q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!8w5q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!8w5q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8w5q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1827340,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/214373289?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8w5q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!8w5q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!8w5q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!8w5q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fda19c-fd6f-49e6-bb38-344f033f039e_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Why Scan Reduction Is the Primary Lever</h2><p>Athena cost is closely tied to the amount of data scanned.</p><p>That makes scan reduction unusually measurable. If a table moves from full scans to scans that read one-twentieth of the data, the scan volume for those queries can fall dramatically.</p><p>The performance benefit arrives at the same time.</p><p>Analysts feel the difference between a query that takes ninety seconds and one that takes four. Faster queries also encourage more productive exploration, which makes efficient table design a business capability rather than merely a finance exercise.</p><p>The goal is not to make every query cheap.</p><p>The goal is to eliminate repeated, avoidable scans from the tables people use most.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Why Partitioned Tables Still Scan Too Much</h2><p>A table can be partitioned and still receive almost no benefit from partitioning.</p><p>Three mistakes cause most of the damage.</p><h3>The partition key does not match real query behavior</h3><p>A table partitioned by <code>ingest_date</code> may receive queries filtered by <code>event_date</code>.</p><p>The table is technically partitioned. The common queries still scan across the relevant data because they do not constrain the partition key.</p><p>Partition based on how the data is actually queried, not only on how it arrives.</p><h3>A function wraps the partition column</h3><p>Queries that cast, transform, or apply date functions to the partition column may prevent effective pruning.</p><p>For example, this pattern can be problematic:</p><pre><code><code>WHERE CAST(event_date AS DATE) = DATE '2026-09-01'
</code></code></pre><p>Prefer predicates that preserve the column&#8217;s native type and apply the comparison directly:</p><pre><code><code>WHERE event_date &gt;= TIMESTAMP '2026-09-01 00:00:00'
  AND event_date &lt;  TIMESTAMP '2026-09-02 00:00:00'
</code></code></pre><p>The exact syntax depends on the column type. The principle is consistent: make the partition predicate explicit and comparable without wrapping the partition key in a function.</p><h3>Partition metadata is incomplete or expensive</h3><p>Data can exist in [internal] while Athena lacks the corresponding partition metadata.</p><p>The result is missing data, unexpected scans, or repeated crawler and repair work.</p><p>Tables with very large numbers of registered partitions can also develop meaningful metadata-management overhead. At that point, partition projection may be a better fit if the prefix layout is predictable.</p><h2>Three Decisions Per Table</h2><h3>1. What should the partition key be?</h3><p>You usually choose between an ingestion-time column and a business-time column.</p><p><strong><span>Ingestion-time partitioning</span></strong> is simpler operationally. It matches how files arrive and how pipelines typically write data.</p><p><strong><span>Business-time partitioning</span></strong> is often better for query pruning when analysts filter by the date an event actually occurred.</p><p>Look at query history before deciding.</p><p>The predicate that appears in most queries is stronger evidence than the partition convention your ingestion pipeline happens to prefer.</p><h3>2. Should you use catalog partitions or partition projection?</h3><p>Catalog partitions rely on registered metadata, usually maintained through crawlers, repair operations, or explicit partition updates.</p><p>Partition projection defines the partition scheme through table properties. Athena calculates partition locations from the defined pattern instead of requiring every partition to be registered individually.</p><p>Use partition projection when:</p><ul><li><p>The prefix layout is predictable</p></li><li><p>Partition values follow a defined date or enum range</p></li><li><p>The table has many partitions</p></li><li><p>New partitions arrive regularly</p></li><li><p>You want to reduce crawler or repair dependence</p></li></ul><p>Keep catalog partitions when:</p><ul><li><p>The layout is irregular</p></li><li><p>Partition values cannot be derived reliably</p></li><li><p>The table has modest partition counts</p></li><li><p>The data location changes unpredictably</p></li></ul><p>Projection is not automatically better. It requires accurate ranges and predictable paths. A bad projection definition can cause Athena to consider locations that do not exist.</p><h3>3. Should the table be converted to Parquet?</h3><p>Parquet is most valuable for wide tables where queries select a small subset of columns.</p><p>Columnar storage lets Athena read only the required columns, while compression reduces the data transferred and processed.</p><p>Conversion is a stronger candidate when:</p><ul><li><p>The table is queried frequently</p></li><li><p>The table contains many columns</p></li><li><p>Queries select relatively few columns</p></li><li><p>The current format is CSV, JSON, or another row-oriented format</p></li><li><p>The table has meaningful scan volume</p></li></ul><p>Conversion may return less when:</p><ul><li><p>The table is narrow</p></li><li><p>Queries routinely use almost every column</p></li><li><p>The table is rarely queried</p></li><li><p>The conversion process costs more to operate than the scans justify</p></li></ul><p>Do not assume Parquet is valuable because it is modern.</p><p>Measure how much of the table queries actually use.</p><h2>The Optimization Sequence</h2><h3>1. Pull your top five tables</h3><p>Start with the ranked table list from your scan analysis.</p><p>Work in order of aggregate scan volume. Do not spread engineering effort across twenty tables at once.</p><h3>2. Extract the dominant predicates</h3><p>Review the most common <code>WHERE</code> clauses for each table.</p><p>Record:</p><ul><li><p>The columns filtered</p></li><li><p>The date ranges used</p></li><li><p>Whether the partition key appears</p></li><li><p>Whether functions wrap the partition column</p></li><li><p>Whether scheduled queries use bounded predicates</p></li></ul><p>This is the input to every later decision.</p><h3>3. Compare the partition key with real query behavior</h3><p>If the partition key does not match the dominant query predicate, address that before converting formats.</p><p>A perfectly compressed table with the wrong partition key can still scan far more data than necessary.</p><h3>4. Check whether pruning is occurring</h3><p>Compare bytes scanned with the total table size for representative queries.</p><p>A table where queries scan nearly the full table is a candidate for:</p><ul><li><p>A better partition key</p></li><li><p>Corrected predicates</p></li><li><p>Better partition metadata</p></li><li><p>A different table layout</p></li><li><p>A purpose-built aggregate</p></li></ul><p>Do not assume pruning works because the table definition says it is partitioned.</p><p>Verify it in query execution data.</p><h3>5. Move regular layouts to partition projection</h3><p>For tables with predictable date or enum-based prefixes, define the projection properties and test a representative query.</p><p>Compare:</p><ul><li><p>Planning time</p></li><li><p>Total runtime</p></li><li><p>Bytes scanned</p></li><li><p>Query success</p></li><li><p>Results against the previous table</p></li></ul><p>Do not remove the existing metadata process until you've validated the projected table.</p><h3>6. Audit functions on partition columns</h3><p>Search query history for casts and date functions applied directly to partition keys.</p><p>Fix the highest-volume queries first. A one-line rewrite in a dashboard definition can remove repeated full or broad scans.</p><h3>7. Convert qualifying tables to Parquet</h3><p>Write the converted data to a new prefix.</p><p>Use compression such as Snappy for a balanced combination of performance and compatibility.</p><p>Keep the original data until you validate:</p><ul><li><p>Row counts</p></li><li><p>Representative query results</p></li><li><p>Null behavior</p></li><li><p>Timestamp behavior</p></li><li><p>Partition coverage</p></li><li><p>Cost and runtime</p></li></ul><h3>8. Avoid small files</h3><p>Many small files create request and metadata overhead that can reduce Parquet's benefits.</p><p>Target a practical file size in the broad range of 128 MB to 512 MB, then validate against your workload. The right value depends on table size, query patterns, writer behavior, and partition cardinality.</p><p>Small-file problems tend to return unless the writer is configured to prevent them.</p><h3>9. Re-run the measurements</h3><p>After the table has been in use for at least a week, compare it against the baseline:</p><ul><li><p>Total bytes scanned</p></li><li><p>Average bytes scanned per query</p></li><li><p>p95 bytes scanned</p></li><li><p>Query planning time</p></li><li><p>Runtime</p></li><li><p>Monthly scan volume</p></li></ul><p>If scan volume did not fall, stop claiming success.</p><p>Find out whether the partition key, predicates, file layout, or workload was misdiagnosed.</p><h2>The Athena Table Optimization Checklist</h2><p>Use one worksheet per table.</p><p>Record:</p><ul><li><p>Table size</p></li><li><p>Partition count</p></li><li><p>Monthly query count</p></li><li><p>Current average and p95 bytes scanned</p></li><li><p>Current scanned-to-total ratio</p></li><li><p>Top query predicates</p></li><li><p>Current partition key</p></li><li><p>Projection eligibility</p></li><li><p>Average columns selected per query</p></li><li><p>Current file format</p></li><li><p>Average file size</p></li><li><p>Owner</p></li><li><p>Recommended change</p></li><li><p>Before-and-after measurements</p></li></ul><p>Complete the dominant-predicate section before changing the table.</p><p>Every other decision depends on it.</p><h2>What to Measure</h2><p>Track these per optimized table:</p><h3>Scanned-to-total ratio</h3><p>This is your primary pruning signal.</p><p>A low ratio generally indicates that queries are reading a limited portion of the table. A ratio near the full table size indicates that pruning may not be occurring.</p><p>Interpret the ratio alongside query intent. Some analytical queries legitimately require broad scans.</p><h3>Query planning time</h3><p>Rising planning time on a highly partitioned table may indicate that partition metadata is becoming expensive to manage.</p><h3>Average file size</h3><p>A declining average file size indicates that the writer is producing small files again.</p><h3>Monthly bytes scanned</h3><p>This is the number that ultimately matters to the bill.</p><p>Review the top-five ranking quarterly. Usage changes. A table that was insignificant last quarter can become the highest scanner after one new dashboard or reporting workflow goes live.</p><h2>The Return Compounds</h2><p>A correctly partitioned, efficiently formatted table reduces scan volume for future queries.</p><p>That is what makes this work different from negotiating a temporary discount or trimming an instance.</p><p>You are changing the unit economics of the table.</p><p>The return grows as usage grows.</p><p>Athena optimization is not a mystery, and it is not a platform-wide cleanup project.</p><p>It is a measurement problem followed by focused engineering.</p><p>Take your five highest-scan tables.</p><p>Bring the analysts who query them into the room.</p><p>Complete the predicate analysis before changing the table.</p><p>Then fix the highest-impact mismatch first.</p><p>The boring work is the profitable work.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #144: Three Queries That Find Your Athena Cost Problem]]></title><description><![CDATA[Athena bills by bytes scanned. The attribution data exists, but most teams never turn it into an optimization queue.]]></description><link>https://www.thecloudplaybook.com/p/tcp-144-three-queries-that-find-your</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/tcp-144-three-queries-that-find-your</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 04 Oct 2026 14:31:22 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!2lIu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Athena spend is one of the most diagnosable costs in a data platform.</p><p>It is also one of the least diagnosed.</p><p>Athena charges based on data scanned. An analyst writes a query, gets the result, and moves on. The cost appears later as a line item with no obvious owner.</p><p>Then someone notices spend increased and asks the data team to investigate.</p><p>The data team looks at the total.</p><p>That is where the investigation usually stops.</p><p>The useful information is lower in the stack:</p><ul><li><p>Which queries scanned the most?</p></li><li><p>Which tables were involved?</p></li><li><p>Which workgroup or principal submitted them?</p></li><li><p>Were they scheduled reports, dashboards, or exploratory queries?</p></li><li><p>Did partition pruning actually happen?</p></li></ul><p>Athena exposes execution metadata, including bytes scanned and execution time, through query execution history and APIs. Persist that metadata, then turn it into a cost-management table.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2lIu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2lIu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!2lIu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!2lIu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!2lIu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!2lIu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1816206,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/214372804?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2lIu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!2lIu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!2lIu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!2lIu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559b4047-54a9-4478-9cc1-56a6d79a0b6c_1536x1024.png 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Why Expensive Scans Compound</h2><p>An unpartitioned or poorly partitioned table doesn't cost you once.</p><p>It costs you every time someone queries it.</p><p>The worst table is often not the largest table. Large tables frequently receive attention early because their size makes optimization obvious.</p><p>The more dangerous table is often medium-sized, convenient, and queried constantly.</p><p>It started small. Nobody partitioned it. It became central to reporting. Now every dashboard refresh scans the table again.</p><p>The result is not just higher cost.</p><p>It is wasted engineering attention. Without attribution, the response becomes a broad request for &#8220;everyone to optimize their queries.&#8221;</p><p>Broad requests produce shallow effort.</p><p>The actual fix is usually concentrated in two or three tables.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>First, Create a Query History Table</h2><p>The queries below assume you have a normalized table called:</p><p><code>platform_analytics.athena_query_history</code></p><p>With columns such as:</p><ul><li><p><code>query_execution_id</code></p></li><li><p><code>submitted_at</code></p></li><li><p><code>query_text</code></p></li><li><p><code>principal</code></p></li><li><p><code>workgroup</code></p></li><li><p><code>data_scanned_bytes</code></p></li><li><p><code>execution_time_ms</code></p></li><li><p><code>referenced_table</code></p></li></ul><p><code>referenced_table</code> should contain one row per table referenced by a query. A query that touches three tables should produce three history rows with the same query execution ID.</p><p>Do not pretend native query history is a permanent warehouse. Persist it to [internal] or another governed store if you need longer-term analysis. </p><h2>Query 1: Which Tables Drive Total Scan Volume?</h2><pre><code><code>SELECT
    referenced_table,
    COUNT(DISTINCT query_execution_id) AS query_count,
    SUM(data_scanned_bytes) / POWER(1024, 4) AS tebibytes_scanned,
    AVG(data_scanned_bytes) / POWER(1024, 3) AS avg_gib_scanned
FROM platform_analytics.athena_query_history
WHERE submitted_at &gt;= current_timestamp - INTERVAL '30' DAY
GROUP BY referenced_table
ORDER BY tebibytes_scanned DESC
LIMIT 25;
</code></code></pre><p>This ranks tables by aggregate scan volume over the last 30 days.</p><p>That is more useful than finding the single most expensive query. A table scanned moderately by hundreds of queries may cost more than one table scanned heavily once.</p><p>Start with the top three tables.</p><p>Do not optimize the entire lake.</p><h2>Query 2: Who or What Is Driving the Spend?</h2><pre><code><code>SELECT
    principal,
    workgroup,
    COUNT(DISTINCT query_execution_id) AS query_count,
    SUM(data_scanned_bytes) / POWER(1024, 4) AS tebibytes_scanned,
    AVG(data_scanned_bytes) / POWER(1024, 3) AS avg_gib_scanned
FROM platform_analytics.athena_query_history
WHERE submitted_at &gt;= current_timestamp - INTERVAL '30' DAY
GROUP BY principal, workgroup
ORDER BY tebibytes_scanned DESC
LIMIT 25;
</code></code></pre><p>This gives you attribution.</p><p>Not to assign blame.</p><p>To identify the type of fix required.</p><p>If scheduled dashboards dominate, optimize refresh queries and table design.</p><p>If one workgroup dominates, apply workgroup-level controls and review its consumers.</p><p>If exploratory users dominate, improve table documentation, examples, partition guidance, and query education.</p><p>The same cost requires different interventions depending on its source.</p><h2>Query 3: Which Tables Are Being Scanned Almost in Full?</h2><p>To run this query, maintain a second table with one row per table:</p><p><code>platform_analytics.athena_table_inventory</code></p><p>Required columns:</p><ul><li><p><code>referenced_table</code></p></li><li><p><code>table_size_bytes</code></p></li></ul><pre><code><code>WITH table_scan_stats AS (
    SELECT
        referenced_table,
        COUNT(DISTINCT query_execution_id) AS query_count,
        SUM(data_scanned_bytes) AS total_scanned_bytes,
        AVG(data_scanned_bytes) AS avg_scanned_bytes
    FROM platform_analytics.athena_query_history
    WHERE submitted_at &gt;= current_timestamp - INTERVAL '30' DAY
    GROUP BY referenced_table
)
SELECT
    s.referenced_table,
    s.query_count,
    s.avg_scanned_bytes / POWER(1024, 3) AS avg_gib_scanned,
    i.table_size_bytes / POWER(1024, 3) AS table_size_gib,
    s.avg_scanned_bytes / NULLIF(i.table_size_bytes, 0) AS avg_scan_ratio
FROM table_scan_stats s
JOIN platform_analytics.athena_table_inventory i
    ON s.referenced_table = i.referenced_table
WHERE s.avg_scanned_bytes / NULLIF(i.table_size_bytes, 0) &gt;= 0.80
ORDER BY s.total_scanned_bytes DESC;
</code></code></pre><p>A high ratio means queries are scanning most of the table on average.</p><p>That makes partitioning, file format, predicate use, or table redesign a likely optimization target.</p><p>The ratio is a screening signal, not proof. A full scan may be intentional for some workloads. Confirm the query patterns before changing the table.</p><h2>What to Do With the Results</h2><p>For each of the top three tables, record:</p><ul><li><p>Owner</p></li><li><p>Primary consumers</p></li><li><p>Query count</p></li><li><p>Total bytes scanned</p></li><li><p>Average scan ratio</p></li><li><p>Partition scheme</p></li><li><p>File format</p></li><li><p>Most common predicates</p></li><li><p>Recommended fix</p></li><li><p>Expected completion date</p></li></ul><p>Then choose one optimization queue.</p><p>Do not send the results to everyone with a request to &#8220;use Athena more efficiently.&#8221;</p><p>Assign one owner to each table and fix the highest-impact problem first.</p><p>The usual candidates are:</p><ul><li><p>Add or repair partitioning</p></li><li><p>Convert text formats to columnar formats</p></li><li><p>Add date predicates to scheduled queries</p></li><li><p>Reduce dashboard refresh frequency</p></li><li><p>Separate raw and analytical tables</p></li><li><p>Create an aggregate table for repeated reporting</p></li><li><p>Move an unsuitable workload to another query engine</p></li></ul><p>The first win should be measurable.</p><p>Compare bytes scanned before and after the change.</p><h2>What to Measure Monthly</h2><p>Track:</p><ul><li><p>Total bytes scanned</p></li><li><p>p95 bytes scanned per query</p></li><li><p>Top five tables by scan volume</p></li><li><p>Top five principals or workgroups by scan volume</p></li><li><p>Number of tables with average scan ratio above 0.80</p></li><li><p>Athena cost per active analyst or consuming team</p></li><li><p>Time required to identify the owner of an expensive table</p></li></ul><p>The goal is not to make every query cheap.</p><p>The goal is to stop paying repeatedly for the same avoidable waste.</p><p>Athena costs become manageable when you have attribution, owners, and a recurring review cadence.</p><p>Every expensive Athena environment has the same failure mode:</p><p>The data needed to diagnose the problem exists.</p><p>Nobody turns it into a queue.</p><p>Run the three queries today. Find the top three tables. Assign owners. Fix one before optimizing anything else.</p><p>That is how a mysterious line item becomes an operating metric.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #142: ETL vs ELT Is Not a Platform-Wide Decision]]></title><description><![CDATA[Standardizing every pipeline on one pattern is how teams overpay for compute or create unnecessary latency.]]></description><link>https://www.thecloudplaybook.com/p/etl-vs-elt-decision-tree</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/etl-vs-elt-decision-tree</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 20 Sep 2026 14:31:02 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!YZKY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most data platform teams answer the ETL versus ELT question once, at the platform level, and apply that answer to every pipeline.</p><p>The reasoning is understandable.</p><p>One pattern means fewer tools, fewer skills to maintain, fewer failure modes, and simpler runbooks. Standardization helps platform teams stay sane.</p><p>Then the portfolio grows.</p><p>A pipeline loads terabytes of raw data into the warehouse, performs an expensive transformation, and produces a small aggregate. The organization pays warehouse compute to process data that could have been reduced earlier.</p><p>Another pipeline transforms too aggressively before loading. Six months later, an analyst needs detail that was discarded during ingestion. Reconstructing it requires a source-system project nobody planned for.</p><p>The pattern choice is not a permanent platform standard.</p><p>It is a per-pipeline decision with cost, latency, flexibility, and compliance consequences.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YZKY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YZKY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!YZKY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!YZKY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!YZKY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YZKY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2034590,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/214369305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YZKY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!YZKY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!YZKY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!YZKY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3541070b-49c0-4af0-9d8d-d6f1bbfb77d1_1448x1086.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>What ETL and ELT Actually Trade</h2><p><strong><span>ETL</span></strong> means extract, transform, then load.</p><p>The data is transformed before it reaches the analytical destination.</p><p><strong><span>ELT</span></strong> means extract, load, then transform.</p><p>The raw or lightly processed data lands first, and transformations happen inside the warehouse or lakehouse.</p><p>Neither pattern is universally better.</p><p>ETL is useful when you need to reduce data volume before loading, apply controls before broader access, or run stable and computationally heavy transformations outside the warehouse.</p><p>ELT is useful when you want to preserve raw data, iterate quickly on transformation logic, and let analysts modify SQL without requiring an engineering deployment.</p><p>The mistake is treating either pattern as an ideology.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Why the Wrong Choice Appears in the Warehouse Bill</h2><p>ELT deliberately uses warehouse compute for transformation.</p><p>That is often a good trade. You preserve raw data, simplify ingestion, and keep business logic close to the analysts who change it.</p><p>The trade becomes less attractive when:</p><ul><li><p>The transformation runs on every load</p></li><li><p>The input is much larger than the output</p></li><li><p>The transformation is computationally heavy</p></li><li><p>The output discards most of the source data</p></li><li><p>The warehouse is already capacity-constrained</p></li></ul><p>Loading two terabytes to produce a four-gigabyte aggregate may still be the right choice if the raw data has analytical value.</p><p>But if the raw data is never queried, must be reduced before access, and is expensive to transform repeatedly, ETL deserves serious consideration.</p><p>Do not optimize based on the size of the final table alone. Compare:</p><ul><li><p>Input volume</p></li><li><p>Output volume</p></li><li><p>Transformation frequency</p></li><li><p>Compute cost</p></li><li><p>Retention requirements</p></li><li><p>Future analytical value of the raw data</p></li></ul><h2>Why Latency Changes the Answer</h2><p>ETL adds a processing stage before the data reaches its destination.</p><p>That can increase freshness latency.</p><p>For a dashboard that genuinely requires data every five minutes, an additional transformation stage may be unacceptable. ELT, micro-batching, or streaming may be a better fit.</p><p>But many freshness requirements are inherited rather than measured.</p><p>A team says a dashboard needs five-minute freshness because that was written in an old requirements document. The dashboard is reviewed once each morning.</p><p>That is not a five-minute business requirement. It is an unchallenged assumption.</p><p>Before choosing a lower-latency pattern, ask how quickly someone must act on the data. Freshness is valuable when it changes a decision, not merely because the pipeline can be made faster.</p><h2>Why Compliance Changes the Answer</h2><p>Compliance does not automatically mean every sensitive pipeline must use ETL.</p><p>The real question is:</p><blockquote><p><em>Can raw sensitive data land in the destination under an access model that prevents unauthorized users from seeing it?</em></p></blockquote><p>If the answer is no, sensitive fields must be masked, tokenized, filtered, or otherwise controlled before they reach the broadly accessible analytical layer.</p><p>That may require ETL.</p><p>In other architectures, raw data can land in a tightly restricted zone while a governed transformation produces the analyst-facing tables.</p><p>The requirement is not &#8220;always use ETL.&#8221;</p><p>The requirement is that sensitive data does not become broadly accessible before the required controls are applied.</p><p>Document where the control happens, who can access the raw layer, and how the transformed layer is verified.</p><h2>The Four Questions to Ask for Every Pipeline</h2><h3>1. What is the input-to-output ratio?</h3><p>If a pipeline consistently reduces a large source into a much smaller analytical output, evaluate ETL.</p><p>A high reduction ratio does not automatically settle the decision. Raw data may still be valuable for future analysis, audits, or reprocessing.</p><p>But repeatedly paying warehouse compute to discard most of the input is a clear signal to investigate.</p><h3>2. Does the pipeline contain sensitive data?</h3><p>Identify whether the source includes:</p><ul><li><p>Personal information</p></li><li><p>Financial information</p></li><li><p>Health information</p></li><li><p>Credentials or secrets</p></li><li><p>Customer-level behavioral data</p></li><li><p>Regulated operational data</p></li></ul><p>Then define the first point at which unauthorized access is technically prevented.</p><p>If sensitive data must be controlled before it reaches the general warehouse, transform before that boundary.</p><h3>3. How stable is the transformation logic?</h3><p>Frequently changing business logic often belongs in ELT.</p><p>Analysts can iterate in SQL, compare versions, and update transformations without rebuilding the ingestion system.</p><p>Stable, computationally heavy transformations are stronger ETL candidates, especially when they reduce data substantially before loading.</p><p>Do not confuse &#8220;stable&#8221; with &#8220;important.&#8221; A metric can be business-critical and still change frequently.</p><h3>4. What freshness requirement is real?</h3><p>Classify the pipeline based on the action it supports:</p><ul><li><p>Daily reporting</p></li><li><p>Hourly operational review</p></li><li><p>Near-real-time monitoring</p></li><li><p>Automated decisioning</p></li><li><p>User-facing product behavior</p></li></ul><p>Then measure the acceptable delay.</p><p>A pipeline that supports daily reporting does not need a five-minute architecture. A pipeline that triggers fraud controls may.</p><h2>A Practical Decision Rule</h2><p>Use ETL when most of the following are true:</p><ul><li><p>The transformation is computationally heavy</p></li><li><p>The output is dramatically smaller than the input</p></li><li><p>The logic is stable</p></li><li><p>Sensitive fields must be controlled before broad access</p></li><li><p>Extra processing latency is acceptable</p></li></ul><p>Use ELT when most of the following are true:</p><ul><li><p>Raw data has ongoing analytical value</p></li><li><p>Transformation logic changes frequently</p></li><li><p>Analysts need direct SQL control</p></li><li><p>The pipeline requires very low latency</p></li><li><p>Warehouse capacity can support the transformation workload</p></li></ul><p>When the signals conflict, resolve them in this order:</p><ol><li><p>Security and compliance requirements</p></li><li><p>Real freshness requirement</p></li><li><p>Input-to-output economics</p></li><li><p>Transformation volatility</p></li><li><p>Platform simplicity</p></li></ol><p>This keeps cost from overriding a control requirement and prevents inherited latency assumptions from dictating every design.</p><h2>What Per-Pipeline Decisions Return</h2><p>Teams that evaluate pipelines individually usually end up with a portfolio rather than a religion.</p><p>High-reduction and control-sensitive pipelines use ETL where it creates a clear economic or security advantage.</p><p>Stable-volume pipelines with frequently changing business logic use ELT where analyst flexibility is worth the warehouse cost.</p><p>The platform still has standards.</p><p>The standard is not &#8220;everything uses ETL&#8221; or &#8220;everything uses ELT.&#8221;</p><p>The standard is the decision process.</p><p>Track the choice for each pipeline:</p><ul><li><p>Selected pattern</p></li><li><p>Reason for selection</p></li><li><p>Expected cost profile</p></li><li><p>Freshness target</p></li><li><p>Data sensitivity</p></li><li><p>Review trigger</p></li></ul><p>Revisit the choice when the pipeline&#8217;s volume, consumers, sensitivity, or latency requirement changes.</p><p>Supporting two patterns creates real operational overhead.</p><p>It is still cheaper than forcing every pipeline into a pattern that fits half the portfolio.</p><p>A platform default is useful.</p><p>A default nobody is allowed to revisit becomes technical debt with a governance committee.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #141: Seven Signals Your Organization Is Not Ready for Data Mesh]]></title><description><![CDATA[Decentralizing data ownership before the platform exists produces silos with better branding.]]></description><link>https://www.thecloudplaybook.com/p/data-mesh-readiness-audit</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/data-mesh-readiness-audit</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 13 Sep 2026 14:30:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!AXDa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Data mesh usually arrives as an answer to a real problem.</p><p>The central data team is a bottleneck. Dashboard requests queue behind one another. Domain teams understand their own data best, but wait weeks for someone else to model it.</p><p>Decentralizing ownership sounds like the obvious solution.</p><p>So the organization announces a data mesh. Domains become responsible for their own data products. The central data team becomes a platform team.</p><p>Twelve months later, there are nine domain data teams, no shared discovery layer, four definitions of &#8220;active customer,&#8221; and an executive asking why two reports show different revenue numbers.</p><p>The bottleneck is gone.</p><p>So is the coherence.</p><p>Nobody necessarily made a bad decision. The organization decentralized ownership before building the capabilities that make decentralized ownership work.</p><p><strong><span>Domain ownership without self-service infrastructure, data products, and federated governance is not a data mesh. It is decentralization with better branding.</span></strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AXDa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AXDa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!AXDa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!AXDa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!AXDa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!AXDa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/af9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2242371,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/214370310?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AXDa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!AXDa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!AXDa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!AXDa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf9a5828-cc58-4c2b-bcdc-a9ec347c7d0f_1448x1086.png 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Why a Premature Data Mesh Costs More Than the Bottleneck</h2><p>The central data team may have been slow, but it was also quietly performing four jobs:</p><ol><li><p>Enforcing consistent metric definitions</p></li><li><p>Helping people discover available datasets</p></li><li><p>Acting as a quality gate</p></li><li><p>Controlling access to sensitive data</p></li></ol><p>When ownership is decentralized without replacing those functions, they do not automatically transfer to the domains.</p><p>They stop happening.</p><p>The cost appears as reconciliation work. Finance and product report different revenue numbers, and a senior analyst spends three days tracing the discrepancy.</p><p>That work rarely appears on a roadmap. It still consumes real capacity.</p><p>The second cost is duplicated infrastructure. Each domain builds its own pipelines, cataloging process, quality checks, and access workflow. Platform spending increases without a proportional increase in what the business can answer.</p><p>The third cost is loss of trust.</p><p>Once consumers cannot tell which dataset is authoritative, they create private copies. Those copies develop their own definitions, owners, and freshness characteristics.</p><p>You have not created a mesh.</p><p>You have created multiple competing versions of reality.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Why Capable Teams Decentralize Too Early</h2><p>Data mesh is often adopted as an organizational fix for a technical constraint.</p><p>The pressure is immediate. The central team is overloaded, and business stakeholders want faster delivery.</p><p>Reorganizing is something leadership can do this quarter.</p><p>Building a self-service data platform is a multi-quarter engineering investment. For much of that period, the work produces infrastructure rather than visible business features.</p><p>When given a choice between movement now and results later, organizations usually choose movement.</p><p>That is why the sequencing fails.</p><p>Data mesh has four commonly cited principles:</p><ul><li><p>Domain ownership</p></li><li><p>Data as a product</p></li><li><p>Self-serve data infrastructure</p></li><li><p>Federated computational governance</p></li></ul><p>The first principle is easy to announce. The other three are harder to show in an org chart, so they become aspirations in a strategy document.</p><p>Domain ownership without the other three produces local autonomy without shared standards, discoverability, or reliable access.</p><p>That is not a mesh. It is a collection of silos.</p><h2>The Seven-Signal Data Mesh Readiness Audit</h2><p>Answer each question honestly.</p><p>Each &#8220;no&#8221; identifies a capability you need to build before expanding domain ownership.</p><h3>1. Can a domain team publish a new data product without filing a ticket with the central team?</h3><p>If every new dataset requires a platform engineer to create pipelines, configure storage, register metadata, or grant access, you have not removed the bottleneck.</p><p>You have renamed it.</p><p>A real mesh requires a paved path that lets domain teams publish within defined standards without needing custom platform intervention every time.</p><h3>2. Is there one place where anyone can discover available data products?</h3><p>A consumer should be able to find:</p><ul><li><p>What data products exist</p></li><li><p>Who owns them</p></li><li><p>What they contain</p></li><li><p>How fresh they are</p></li><li><p>What quality guarantees exist</p></li><li><p>How to request access</p></li></ul><p>Without a shared discovery layer, decentralized ownership becomes decentralized invisibility.</p><p>People cannot use data they cannot find.</p><h3>3. Are your top ten business metrics defined and owned?</h3><p>Do you have written definitions for metrics such as:</p><ul><li><p>Active customer</p></li><li><p>Gross revenue</p></li><li><p>Net revenue</p></li><li><p>Churn</p></li><li><p>Conversion rate</p></li><li><p>Qualified lead</p></li></ul><p>More importantly, does each definition have a named owner?</p><p>Federated governance does not mean every domain defines everything independently. It means accountable owners apply shared standards locally.</p><p>Without shared definitions, you do not have federation.</p><p>You have local interpretation.</p><h3>4. Can one domain grant another domain access without involving a platform engineer?</h3><p>Access friction creates shadow copies.</p><p>If a product team needs customer data and must wait two weeks for a platform engineer to process the request, someone will eventually copy the data into a place they control.</p><p>That may solve the immediate problem.</p><p>It also creates another dataset with another permission model, another freshness risk, and another definition of truth.</p><p>Self-service access is not just a convenience feature. It is a control against uncontrolled duplication.</p><h3>5. Does every existing dataset have a named owner today?</h3><p>Do not assume a reorganization will fix unclear ownership.</p><p>If ownership is ambiguous now, decentralization does not assign accountability. It distributes the ambiguity across more teams.</p><p>Before assigning domain responsibility for new data products, identify who owns the datasets already in production.</p><p>If nobody can answer, start there.</p><h3>6. Do you have data quality contracts?</h3><p>A data quality contract should make expectations explicit between producers and consumers.</p><p>It may cover:</p><ul><li><p>Schema</p></li><li><p>Freshness</p></li><li><p>Completeness</p></li><li><p>Valid value ranges</p></li><li><p>Availability</p></li><li><p>Change notification</p></li></ul><p>Without a contract mechanism, an upstream schema change becomes a downstream incident.</p><p>Domain autonomy is only safe when consumers know what producers have promised to maintain.</p><h3>7. Does anyone treat data as a product today?</h3><p>A data product has more than a table and a pipeline.</p><p>It has:</p><ul><li><p>A defined consumer</p></li><li><p>A clear use case</p></li><li><p>An accountable owner</p></li><li><p>A quality expectation</p></li><li><p>A freshness expectation</p></li><li><p>A way for consumers to provide feedback</p></li></ul><p>If nobody in the organization treats data this way today, a reorganization will not create product thinking by itself.</p><p>You will simply assign ownership of poorly defined datasets to new teams.</p><h2>Score Your Organization</h2><p>Use the following interpretation:</p><ul><li><p><strong><span>6 to 7 yes answers:</span></strong> You may be ready for a controlled data mesh rollout.</p></li><li><p><strong><span>4 to 5 yes answers:</span></strong> Build the missing platform capabilities before expanding domain ownership.</p></li><li><p><strong><span>0 to 3 yes answers:</span></strong> Do not begin with a data mesh reorganization. Your immediate priority is platform readiness.</p></li></ul><p>The score is not a maturity badge.</p><p>It is a sequencing decision.</p><h2>What Correct Sequencing Buys You</h2><p>Organizations that build the platform layer first can decentralize once and keep the model stable.</p><p>Organizations that decentralize first often reverse the decision eighteen months later, after reconciliation costs, duplicated tooling, and loss of trust become impossible to ignore.</p><p>The platform investment pays back before the mesh arrives.</p><p>Self-service pipeline tooling reduces central team intake.</p><p>A discovery catalog reduces duplicate dataset creation.</p><p>Standardized access workflows reduce copying.</p><p>Data quality contracts reduce downstream surprises.</p><p>These capabilities are useful under a centralized model and necessary under a distributed one.</p><p>That is the key sequencing insight:</p><p><strong><span>You do not need to wait for a data mesh to build a platform that supports one.</span></strong></p><p>Fix the bottleneck with platform capability first. Move ownership when the capability exists to support it.</p><p>A reorganization is not an architecture.</p><p>If the platform underneath cannot support autonomy, the org chart change only relocates the problem to a place where it is harder to see.</p><p>Before you announce a data mesh, score your organization against these seven signals.</p><p>If you have fewer than five yes answers, do not start with decentralization.</p><p>Start by building the missing platform capabilities.</p><p>That is how you create a data mesh instead of a collection of silos with better branding.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #140: How to Keep Your AWS Data Lake From Becoming a Data Swamp]]></title><description><![CDATA[A Terraform reference pattern for controlling schema, ownership, partitioning, permissions, and cost before your serverless data lake becomes untrusted.]]></description><link>https://www.thecloudplaybook.com/p/serverless-data-lake-aws-terraform-iac</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/serverless-data-lake-aws-terraform-iac</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 06 Sep 2026 14:31:57 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!szRu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most data lakes do not fail because teams chose the wrong AWS service.</p><p>They fail because nobody encoded ownership, schema authority, partitioning, and access rules before the first dataset arrived.</p><p>The pattern is predictable:</p><p>A team creates an Amazon S3 bucket, points AWS Glue crawlers at it, and queries the data with Amazon Athena.</p><p>It works.</p><p>Six months later, the catalog contains hundreds of tables. Nobody knows which ones are authoritative. Analysts build private copies. Athena queries scan more data than expected. The platform team becomes the human directory for every dataset question.</p><p>The lake has become a data swamp.</p><p>The problem is not serverless architecture. The problem is that the structure was left in documentation, tribal knowledge, and manual cleanup instead of being encoded in infrastructure as code.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!szRu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!szRu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!szRu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!szRu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!szRu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!szRu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2091583,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/214369344?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!szRu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!szRu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!szRu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!szRu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a71cc6e-0b36-47af-9ad0-81ecd67a866e_1448x1086.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>The cost of an unstructured AWS data lake</h2><p>An unstructured data lake bills you twice.</p><p>The direct cost comes from inefficient queries. Without partitioning conventions enforced at ingestion, analysts can scan entire prefixes or large tables when they only need a small date range.</p><p>The second cost is trust.</p><p>When teams cannot answer which table is authoritative, they create their own copies. Eventually, the organization pays for duplicate storage and compute while executives receive reports that do not reconcile.</p><p>The platform team absorbs the organizational cost. They become the routing layer for questions that the data platform should answer automatically:</p><ul><li><p>Which dataset should I use?</p></li><li><p>Who owns this table?</p></li><li><p>Is this data raw, cleaned, or curated?</p></li><li><p>Who can read customer PII?</p></li><li><p>Is this table still supported?</p></li><li><p>Why did this query scan so much data?</p></li></ul><p>The fix is not another dashboard.</p><p>The fix is structure at creation.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Why data lakes accumulate hundreds of untrusted tables</h2><p>The failure usually begins with a reasonable decision:</p><blockquote><p><em>Let teams land data quickly and organize it later.</em></p></blockquote><p>AWS Glue crawlers make this easy. Point a crawler at a prefix and it infers a schema, then registers a table in the Glue Data Catalog.</p><p>That reduces friction. It also removes accountability.</p><p>A crawler-created table may have a schema but no:</p><ul><li><p>Owner</p></li><li><p>Data classification</p></li><li><p>Quality contract</p></li><li><p>Source system</p></li><li><p>Lifecycle policy</p></li><li><p>Statement of authority</p></li></ul><p>By month eleven, the catalog may accurately describe what exists while providing almost no signal about what can be trusted.</p><p>The same pattern appears in permissions. Teams receive ad hoc S3 or IAM access during onboarding. Exceptions accumulate. A year later, answering &#8220;who can read this customer dataset?&#8221; requires reconstructing old tickets, policies, and team decisions.</p><p>That is not governance. That is archaeology.</p><h2>The three design decisions that determine whether the lake holds</h2><h3>1. Separate zones with buckets or prefixes</h3><p>A practical serverless data lake usually has three zones:</p><ul><li><p><strong><span>Raw:</span></strong> Data as received from source systems</p></li><li><p><strong><span>Cleaned:</span></strong> Validated and standardized data</p></li><li><p><strong><span>Curated:</span></strong> Business-ready datasets for consumption</p></li></ul><p>Separate S3 buckets provide cleaner IAM boundaries, independent lifecycle policies, and distinct encryption-key scopes.</p><p>Prefixes inside one bucket are simpler, but they create a weaker security boundary and make policy conditions easier to misconfigure.</p><p>Use separate buckets when you have regulated data, multiple teams writing data, or materially different retention requirements.</p><p>Use prefixes when one team owns the entire lake and the operating model is genuinely simple.</p><p>The important decision is not which structure sounds more elegant. It is whether the boundary will remain explainable as the organization grows.</p><h3>2. Use crawlers selectively</h3><p>Use Glue crawlers for the raw zone when the incoming schema genuinely changes or is outside your control.</p><p>For cleaned and curated data, declare table schemas in Terraform with <code>aws_glue_catalog_table</code>.</p><p>That gives you:</p><ul><li><p>Reviewed schema changes</p></li><li><p>Version history through pull requests</p></li><li><p>Explicit partition keys</p></li><li><p>Consistent storage descriptors</p></li><li><p>A clear owner for every table</p></li></ul><p>A schema change should be visible before it reaches production, not discovered after an automated crawler silently changes the catalog.</p><h3>3. Choose the permission model deliberately</h3><p>IAM-only access is simpler and may be sufficient for a small analytics organization with limited sensitivity and few consuming teams.</p><p>Lake Formation becomes more valuable when you need permissions expressed in data terms:</p><ul><li><p>Database</p></li><li><p>Table</p></li><li><p>Column</p></li><li><p>Data classification</p></li><li><p>Consuming team</p></li></ul><p>Do not adopt Lake Formation because it sounds more enterprise-ready. Adopt it when the organization needs governance that IAM paths cannot express cleanly.</p><p>The mistake is running both systems without deciding which one is authoritative. If you use Lake Formation, define the migration sequence, grant required access first, and remove legacy access only after you have verified the workload path.</p><h2><strong>The Terraform reference pattern</strong></h2><p>Build the lake from five modules:</p><ol><li><p><strong><span>Zone bucket module</span></strong><br>Inputs: zone name, retention period, KMS key ARN, versioning setting<br>Outputs: bucket ARN, read policy, write policy</p></li><li><p><strong><span>Catalog database module</span></strong><br>Defines the logical database for each data domain or zone.</p></li><li><p><strong><span>Catalog table module</span></strong><br>Defines cleaned and curated schemas, partition keys, Parquet configuration, and table properties.</p></li><li><p><strong><span>Lake Formation grant module</span></strong><br>Defines which teams can access which databases, tables, and columns.</p></li><li><p><strong><span>Ingestion pipeline module</span></strong><br>Defines how data moves from raw to cleaned to curated.</p></li></ol><p>Make the module interface fixed. Avoid one-off infrastructure for every new dataset.</p><p>Required metadata should be mandatory:</p><ul><li><p>Owner team</p></li><li><p>Data classification</p></li><li><p>Source system</p></li><li><p>Retention category</p></li><li><p>Zone</p></li></ul><p>A table without an owner should fail the plan, not become a cleanup ticket.</p><p>Encode the partition convention in the ingestion and writer controls. For example:</p><p><code>dataset/ingest_date=YYYY-MM-DD/</code></p><p>Do not rely on a wiki to enforce a convention. Use controlled writer roles, validation, and policy checks so incorrectly shaped data cannot quietly enter the lake.</p><p>Add lifecycle rules when each zone is created. Retention and storage-class transitions are much cheaper to define at creation than retrofit across years of accumulated data.</p><h2>The operating metrics</h2><p>Review these four numbers monthly:</p><ol><li><p><strong><span>Percentage of catalog tables with an owner tag</span></strong><br>Target: 100%.</p></li><li><p><strong><span>Athena bytes scanned at the 95th percentile</span></strong><br>Rising scan volume usually means partitioning or query discipline is degrading.</p></li><li><p><strong><span>Lake Formation grants compared with consuming teams</span></strong><br>Grant growth that dramatically exceeds team growth signals exception accumulation.</p></li><li><p><strong><span>Time required to answer who can read a table</span></strong><br>Target: less than ten minutes.</p></li></ol><p>Review access grants quarterly. Review partitioning and scan behavior monthly with the analytics team.</p><h2>Build a lake you can still explain in year three</h2><p>A well-structured data lake may cost more effort in week one and less money, confusion, and risk every week after.</p><p>Structure encoded at creation is cheap.</p><p>Structure imposed on four hundred existing tables is a reorganization nobody has budgeted for.</p><p>If your lake is already in production, compare the current architecture against the five modules above. Identify which module has no clear equivalent. That gap list is your backlog.</p><p>The goal is not to build the most sophisticated AWS data platform.</p><p>The goal is to build one that remains trusted, governable, and explainable as the organization grows.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #143: The Glue Job That Survives a Mid-Load Failure]]></title><description><![CDATA[Bookmarks, staging merges, late-arriving data, and recovery design for incremental S3-to-Redshift loads.]]></description><link>https://www.thecloudplaybook.com/p/incremental-s3-redshift-etl-glue</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/incremental-s3-redshift-etl-glue</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 06 Sep 2026 02:09:01 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!2v9z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Incremental AWS Glue jobs are usually designed for the happy path:</p><ol><li><p>Read new S3 files.</p></li><li><p>Transform the data.</p></li><li><p>Write to Amazon Redshift.</p></li><li><p>Finish successfully.</p></li></ol><p>They run cleanly for months.</p><p>Then one fails halfway through the load, and the team discovers it cannot answer a basic question:</p><blockquote><p><em>Which rows actually made it into Redshift?</em></p></blockquote><p>That is when an ordinary pipeline failure becomes a data correctness incident.</p><p>The problem is not that the job failed.</p><p>The problem is that the pipeline has no reliable way to distinguish:</p><ul><li><p>Data that was read</p></li><li><p>Data that was transformed</p></li><li><p>Data that reached staging</p></li><li><p>Data that reached the target table</p></li><li><p>Data that was committed successfully</p></li></ul><p>A production pipeline must make those states observable and recoverable.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2v9z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2v9z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png 424w, https://substackcdn.com/image/fetch/$s_!2v9z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png 848w, https://substackcdn.com/image/fetch/$s_!2v9z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png 1272w, https://substackcdn.com/image/fetch/$s_!2v9z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!2v9z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png" width="1226" height="1283" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1283,&quot;width&quot;:1226,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1908783,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/214372008?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2v9z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png 424w, https://substackcdn.com/image/fetch/$s_!2v9z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png 848w, https://substackcdn.com/image/fetch/$s_!2v9z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png 1272w, https://substackcdn.com/image/fetch/$s_!2v9z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d42d23d-67e7-4f2a-89d0-1baaf3211e85_1226x1283.png 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Why Partial Loads Cost More Than Failed Loads</h2><p>A clean failure is an alert and a rerun.</p><p>A partial load is different. Downstream dashboards may show incomplete numbers that still look plausible. Nobody notices until an analyst finds a total that does not reconcile, sometimes days later.</p><p>You cannot safely rerun the entire job if some rows already landed. The rerun may duplicate those rows.</p><p>The recovery process becomes manual:</p><ul><li><p>Reconstruct which files were processed</p></li><li><p>Identify which rows reached Redshift</p></li><li><p>Delete partial data</p></li><li><p>Rerun a subset</p></li><li><p>Validate the result under production pressure</p></li></ul><p>The business cost is even higher. Decisions may have been made using incomplete data during the gap.</p><p>That cost rarely appears in the incident report.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Why Glue Job Bookmarks Are Not Idempotency</h2><p>Glue job bookmarks are useful, but they solve a narrower problem than many teams assume.</p><p>A bookmark tracks source objects that a job has processed. It is not a record of what was successfully committed to the downstream target.</p><p>Imagine a job reads 100 files, writes data from 60 of them to Redshift, and then fails.</p><p>The bookmark may remain unadvanced. The rerun reads the 100 files again.</p><p>Without an idempotent write strategy, those 60 files can be inserted twice.</p><p>The bookmark did not fail.</p><p>It tracked source progress. It did not guarantee destination correctness.</p><p>Late-arriving data creates a second problem. A file containing yesterday&#8217;s records may arrive today. Depending on the source layout and bookmark behavior, the file may be missed, reprocessed, or require a broader partition scan.</p><p>You need both:</p><ul><li><p>A mechanism that finds the right source data</p></li><li><p>A mechanism that makes the destination write safe to repeat</p></li></ul><h2>The Three Decisions That Determine Reliability</h2><h3>1. Staging merge or delete-and-insert?</h3><p>Use a staging table plus <code>MERGE</code> when:</p><ul><li><p>You have a dependable business key</p></li><li><p>Existing records can be updated</p></li><li><p>You need exact upsert behavior</p></li><li><p>Duplicate prevention matters across reruns</p></li></ul><p>Use delete-and-insert by partition when:</p><ul><li><p>The data is append-only</p></li><li><p>The partition is the natural unit of reprocessing</p></li><li><p>The entire partition can be rebuilt safely</p></li><li><p>You do not have a reliable primary key</p></li></ul><p>Delete-and-insert is simpler, but only correct when the partition is fully reprocessable.</p><p>If new records arrive incrementally within the same partition, you may need to delete and rebuild the partition. Deleting only the rows seen in the latest run may leave stale or duplicate data behind.</p><h3>2. Lookback window or event-driven reprocessing?</h3><p>A lookback window reprocesses the last N days on every run.</p><p>This is simple and resilient. It catches late-arriving files without requiring a separate event workflow.</p><p>Start with a three-day window only as an operating default, not as a permanent truth. Measure actual arrival delays and resize the window based on evidence.</p><p>Use event-driven reprocessing when:</p><ul><li><p>Data volume makes repeated lookbacks expensive</p></li><li><p>Late arrivals are rare but costly</p></li><li><p>You can reliably detect affected partitions</p></li><li><p>The team can operate the additional event workflow</p></li></ul><p>The right window is the smallest one that captures your real arrival distribution with an acceptable miss rate.</p><h3>3. Job-level or batch-level recovery?</h3><p>Job-level retry reruns the entire job.</p><p>That is usually sufficient for shorter pipelines.</p><p>Batch-level checkpointing records progress as the job advances and allows recovery from a smaller unit. It adds complexity, but becomes valuable when a full run takes long enough that restarting from zero threatens the load window.</p><p>The decision is economic:</p><blockquote><p><em>How expensive is a full restart when the job fails near completion?</em></p></blockquote><p>If the answer is &#8220;it causes missed SLAs or creates a backlog,&#8221; finer-grained recovery may pay for itself.</p><h2>The Production Pattern</h2><h3>1. Enable bookmarks and stabilize transformation contexts</h3><p>Enable Glue job bookmarks, but treat them as source-discovery state, not destination idempotency.</p><p>Assign stable transformation context names. Refactoring an unnamed context can change how Glue identifies a transformation and may affect bookmark behavior.</p><p>Treat the context name like an interface. Change it deliberately, not incidentally.</p><h3>2. Truncate staging at the beginning of every run</h3><p>Write each run into a staging table with:</p><ul><li><p>The same business columns as the target</p></li><li><p>A batch identifier</p></li><li><p>Source file metadata</p></li><li><p>Ingestion timestamp</p></li></ul><p>Generate the batch identifier from the Glue run ID.</p><p>Truncate staging at job start, not job end.</p><p>If the previous job failed before cleanup, the next run starts from a known state. Cleanup at the end is not enough because failed jobs do not reliably reach the cleanup step.</p><h3>3. Load staging before touching the target</h3><p>Do not write directly into the production table.</p><p>First load the source data into staging. Then validate it.</p><p>Before the target changes, verify:</p><ul><li><p>Expected source objects were found</p></li><li><p>Staged row count is within tolerance</p></li><li><p>Required columns are present</p></li><li><p>Business keys are not unexpectedly duplicated</p></li><li><p>Transformation errors are below threshold</p></li></ul><p>This separates ingestion failure from target corruption.</p><h3>4. Merge into Redshift as one transaction</h3><p>After validation, merge staging into the target within a single transaction.</p><p>The transaction should either apply the batch completely or apply none of it.</p><p>That converts a partial target write into a clean failure that can be retried.</p><p>Make sure the merge key is actually stable. A weak or non-unique key can create updates that look successful while corrupting the target&#8217;s logical grain.</p><h3>5. Apply the lookback in the source query</h3><p>Use the lookback window in the source predicate, typically against the partition column.</p><p>The bookmark and the lookback solve different problems:</p><ul><li><p>The bookmark tracks previously seen source objects.</p></li><li><p>The lookback checks a bounded historical range for late data.</p></li></ul><p>You need both when files can arrive after their logical event date.</p><h3>6. Reconcile before committing</h3><p>Compare source and staged counts before the merge.</p><p>At minimum, log and validate:</p><ul><li><p>Source object count</p></li><li><p>Source row count, if available</p></li><li><p>Staged row count</p></li><li><p>Rejected row count</p></li><li><p>Duplicate-key count</p></li><li><p>Batch identifier</p></li></ul><p>A nonzero variance should either fail the batch or trigger a defined tolerance rule.</p><p>Do not invent tolerance thresholds during an incident.</p><h3>7. Prevent concurrent runs</h3><p>Set maximum concurrency to one for pipelines sharing a staging table or target merge path.</p><p>Concurrent runs create race conditions around:</p><ul><li><p>Staging truncation</p></li><li><p>Batch identifiers</p></li><li><p>Merge order</p></li><li><p>Late-arriving data</p></li><li><p>Bookmark state</p></li></ul><p>Retry storms are exactly when these bugs appear. Remove concurrency as a variable unless the pipeline was designed for it.</p><h3>8. Log the state required for recovery</h3><p>Emit structured logs containing:</p><ul><li><p>Batch identifier</p></li><li><p>Glue run ID</p></li><li><p>Source object count</p></li><li><p>Staged row count</p></li><li><p>Target row count</p></li><li><p>Merge start and end time</p></li><li><p>Final status</p></li><li><p>Lookback window used</p></li></ul><p>When someone asks which rows landed, the answer should be one query away.</p><h3>9. Set the timeout below the load window</h3><p>Do not rely on the default Glue timeout.</p><p>Set the timeout based on the operational window available for the pipeline. A hung job that consumes the entire window can delay every downstream run.</p><p>One late load can become a backlog if the pipeline has no recovery margin.</p><h2>Recovery Runbook</h2><p>Create a one-page runbook attached to the job alert.</p><p>It should classify at least four states:</p><ol><li><p><strong><span>Failed before staging write</span></strong><br>Confirm staging is empty for the batch. Rerun safely.</p></li><li><p><strong><span>Failed during staging write</span></strong><br>Confirm the batch&#8217;s staged rows. Truncate staging, then rerun.</p></li><li><p><strong><span>Failed before merge commit</span></strong><br>Confirm the target contains no committed rows for the batch. Rerun after validation.</p></li><li><p><strong><span>Failed after merge commit</span></strong><br>Confirm target state using the batch identifier. Do not blindly rerun. Reconcile first.</p></li></ol><p>The runbook should include queries for:</p><ul><li><p>Batch state</p></li><li><p>Staged row count</p></li><li><p>Target row count</p></li><li><p>Duplicate business keys</p></li><li><p>Source object list</p></li><li><p>Late-arriving files</p></li></ul><p>Fill in tolerance thresholds with the data owner before production. Deciding what variance is acceptable during an incident produces bad decisions.</p><h2>What to Measure</h2><p>Track these per pipeline:</p><ul><li><p>Merge duration as a percentage of total runtime</p></li><li><p>Source-to-staging row-count variance</p></li><li><p>Manual recoveries per month</p></li><li><p>Late arrivals outside the lookback window</p></li><li><p>Time from failure alert to confirmed data state</p></li></ul><p>Targets:</p><ul><li><p>Row-count variance: zero unless explicitly explained</p></li><li><p>Manual recovery: zero</p></li><li><p>Confirmed data state: under fifteen minutes</p></li><li><p>Late arrivals outside the window: rare enough to justify the operating cost</p></li></ul><p>Review late-arrival behavior quarterly. Review failures and recovery time monthly.</p><h2>Build a Load You Do Not Have to Watch</h2><p>A production pipeline does not eliminate failure.</p><p>It makes failure safe, visible, and recoverable.</p><p>With bookmarks, staging, idempotent writes, bounded lookbacks, transactional merges, and structured recovery logs, a mid-load failure becomes an alert and a rerun instead of a data investigation.</p><p>A pipeline that only works when nothing goes wrong is not a production pipeline.</p><p>It is a demo that has not been tested yet.</p><p>Take your three highest-volume incremental loads and classify each against the four failure states above.</p><p>Any pipeline where you cannot answer which state a failure leaves you in is your first candidate to rebuild.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #139: The strangler fig that strangled nothing after 18 months]]></title><description><![CDATA[A strangler fig sequencing checklist for decomposing a monolith on AWS. How to pick which seam to cut first, second, and third, so the pattern converges instead of stalling halfway through.]]></description><link>https://www.thecloudplaybook.com/p/strangler-fig-sequencing-checklist</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/strangler-fig-sequencing-checklist</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 16 Aug 2026 15:03:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!duex!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Eighteen months ago, this team adopted the strangler fig pattern to decompose their monolith.</p><p>Today they have exactly <strong><span>two</span></strong> services extracted. Both projects are frozen.</p><p>The pattern was fine: route traffic through a facade, peel off one capability at a time into its own service, shrink the monolith until there&#8217;s nothing left to strangle.</p><p>It&#8217;s the industry&#8209;standard answer to &#8220;how do we decompose this without a rewrite&#8221; for a reason: it avoids the big&#8209;bang rewrite that kills most modernization efforts.</p><p>But a <strong><span>pattern</span></strong> is not a <strong><span>plan</span></strong>.</p><ul><li><p>Service #1 was picked because an architect had a strong opinion</p></li><li><p>Service #2 was picked because a team volunteered</p></li><li><p>Service #3 never got picked because nobody has a reason for one seam over another</p></li></ul><p>The strangler fig didn&#8217;t fail. <strong><span>Sequencing</span></strong> did.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!duex!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!duex!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!duex!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!duex!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!duex!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!duex!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1725290,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/210482008?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!duex!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!duex!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!duex!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!duex!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c13924-86fb-43b2-a83e-e9cd3b19cec4_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2><strong>Why a Stalled Decomposition Is Worse Than No Decomposition</strong></h2><p>A monolith that never started decomposing is a known, stable cost.</p><p>A monolith that <strong><span>stalled halfway</span></strong> is a compounding one.</p><ul><li><p>The facade/routing layer is now permanent infrastructure to maintain and debug</p></li><li><p>Two teams now own two services <em>plus</em> the monolith = more surface area, not less</p></li><li><p>&#8220;Independent deployability&#8221; exists for a tiny slice of the system, but the overhead is everywhere</p></li></ul><p>The benefits were supposed to justify the cost <strong><span>across the whole estate</span></strong>, not two endpoints.</p><p>Worse, a stalled strangler erodes political capital:</p><ul><li><p>Every quarter without visible progress makes the next planning cycle ask, &#8220;Why are we still funding this?&#8221;</p></li><li><p>A modernization program that can&#8217;t show acceleration starts to look like one that should be cut</p></li></ul><p>The biggest risk with strangler fig was never &#8220;can we write the code.&#8221;<br>It was &#8220;can we keep organizational patience long enough to see compounding benefit.&#8221;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2><strong>Why Sequencing Gets Skipped</strong></h2><p>Even teams that implement the pattern correctly stall because the literature explains <strong><span>how</span></strong> to cut a seam and says almost nothing about <strong><span>which seam you cut next.</span></strong></p><p>So the default becomes:</p><ul><li><p>Whoever yells loudest claims the next capability</p></li><li><p>Or the team that&#8217;s free &#8220;volunteers&#8221; for some random slice of the monolith</p></li></ul><p>You get one extraction that proves the pattern is technically possible, but teaches you nothing about <strong><span>how to prioritize</span></strong> the other nine seams.</p><p>Momentum from the first service doesn&#8217;t transfer, because no one defined what made that seam a good choice in a way you can reuse.</p><p>Complicating it: most monoliths don&#8217;t have neat, obvious seams.</p><ul><li><p>Some capabilities share tables and code with three others</p></li><li><p>Some are already almost independent, and you just haven&#8217;t admitted it</p></li></ul><p>Without a scoring framework, teams default to:</p><ul><li><p>Extracting the <strong><span>easiest</span></strong> seam (often least valuable to isolate), or</p></li><li><p>Extracting the <strong><span>most important</span></strong> seam (often the most coupled and riskiest)</p></li></ul><p>Both patterns look busy, and both fail to converge.</p><div><hr></div><h2><strong>The Sequencing Framework: Score Every Seam on 3 Axes</strong></h2><p>Before extracting anything, list candidate seams and score each one on three axes.</p><p>The scores decide the order. Not titles. Not volunteers.</p><p><strong><span>1. Coupling: how entangled is this capability?</span></strong></p><ul><li><p>Reads/writes mostly its own tables, with a narrow, clear interface &#8594; <strong><span>high score</span></strong> (good early candidate)</p></li><li><p>Reaches into 5 shared tables that 3 other capabilities also mutate &#8594; <strong><span>low score</span></strong> (leave for later)</p></li></ul><p>Early extractions should teach the team the <strong><span>pattern</span></strong>, not force data&#8209;ownership wars.</p><p><strong><span>2. Change frequency: how often does this code change vs the rest of the monolith?</span></strong></p><ul><li><p>Changes weekly, competing for deploy slots and reviews &#8594; extracting it pays off immediately in deploy velocity</p></li><li><p>Hasn&#8217;t changed in 2 years &#8594; clean seam or not, business impact of extraction is low</p></li></ul><p>This is where the <strong><span>business case</span></strong> for extraction actually lives.</p><p><strong><span>3. Blast radius: what else breaks if this service misbehaves after extraction?</span></strong></p><ul><li><p>Narrow, well&#8209;understood set of downstream dependents &#8594; safer to extract early</p></li><li><p>Half the monolith calls into it transitively &#8594; extract later, when the team has more practice operating the new shape</p></li></ul><p>First services should be <strong><span>low&#8209;coupling, high&#8209;change, low&#8209;blast&#8209;radius</span></strong>:</p><ul><li><p>Come out cleanly</p></li><li><p>Prove value quickly</p></li><li><p>Fail safely if something goes wrong</p></li></ul><p>High&#8209;coupling, high&#8209;blast&#8209;radius seams come later, when extraction and incident handling in the new world are muscle memory.</p><div><hr></div><h2><strong>What Sequenced Decomposition Looks Like a Year In</strong></h2><p>A sequenced strangler doesn&#8217;t produce &#8220;two services and a stall.&#8221; It produces a visible curve.</p><p>After a year, you can point to:</p><ul><li><p>X capabilities now independently deployable</p></li><li><p>Y% of changes flowing through services instead of the monolith</p></li><li><p>Incidents that used to take down everything now contained to a single service</p></li></ul><p>That curve is what protects the program when budget season comes.</p><p>A modernization effort that can show three good extractions in the first two quarters, each easier than the last because the team is getting better at the pattern, doesn&#8217;t have to beg to keep going.</p><p>It has evidence.</p><p>The payoff isn&#8217;t just an architecture that eventually decomposes.</p><p>It&#8217;s a program that never has to re&#8209;justify itself every quarter, because the <strong><span>sequencing</span></strong> is the proof that it&#8217;s working.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #138: The rehost business case that was true in the slide deck]]></title><description><![CDATA[Lift-and-shift cost math for AWS rehost migrations. The three line items- instance right-sizing, storage class, and data transfer- that turn a rehost business case from a savings story into a loss.]]></description><link>https://www.thecloudplaybook.com/p/lift-and-shift-cost-math-rehost</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/lift-and-shift-cost-math-rehost</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 09 Aug 2026 16:30:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!J2C0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The rehost business case got approved on a clean story:</p><blockquote><p><em>Move the workload as&#8209;is, shut down the data center, save money.</em></p></blockquote><p>The slide compared on&#8209;prem cost to modeled cloud cost. The savings number looked solid. Finance signed.</p><p>Six months after cutover, the finance review shows the cloud bill <em>higher</em> than the data center line it replaced.</p><p>The migration went exactly as planned. The savings did not.</p><p>Nobody lied. The model was just incomplete.</p><p>A &#8220;lift&#8209;and&#8209;shift&#8221; is not a single decision. It is <strong><span>three cost decisions dressed up as one migration choice</span></strong>.</p><p>Two of those three almost never get modeled before cutover.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!J2C0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!J2C0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!J2C0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!J2C0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!J2C0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!J2C0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1831893,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/210480637?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!J2C0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!J2C0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!J2C0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!J2C0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46e3d24-7916-4667-80f7-7b422cf07d1a_1448x1086.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2><strong>Why This Is a Board&#8209;Level Problem, Not an Engineering Detail</strong></h2><p>A rehost that costs more than the data center it replaced is not a rounding error. It is a <strong><span>credibility hit</span></strong>.</p><p>The program&#8217;s ROI story was built on this math:</p><blockquote><p><em>Per&#8209;workload savings &#215; number of workloads = portfolio business case.</em></p></blockquote><p>When the first big wave lands 30&#8211;40% over estimate, that gap doesn&#8217;t stay local to one app. It becomes the number finance repeats the next time you ask for migration budget.</p><p>And the bad news shows up late:</p><ul><li><p>On&#8209;prem: costs are sunk and mostly fixed. Overprovisioning hides in depreciation.</p></li><li><p>Cloud: costs are variable and visible. Overprovisioning is a monthly bill someone actually reads.</p></li></ul><p>The same workload that quietly overspent in the data center now triggers a finance review <strong><span>every month</span></strong>, and each review re&#8209;litigates whether the whole migration was a mistake.</p><p>Your migration program&#8217;s reputation is set by the <strong><span>first few invoices</span></strong>, not the last one.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2><strong>Why the Estimate and the Invoice Don&#8217;t Match</strong></h2><p>The gap between model and reality almost always traces back to the same three line items.</p><h3><strong>1. Instance right&#8209;sizing</strong></h3><p>Most teams size target instances to match <strong><span>provisioned</span></strong> capacity, not <strong><span>observed</span></strong> utilization.</p><ul><li><p>On&#8209;prem: server sized for a rare peak, used at 20&#8211;30% most of the year.</p></li><li><p>In cloud: lifted 1:1 to an instance that now bills <strong><span>every hour</span></strong> for that peak capacity.</p></li></ul><p>In the data center, that waste was a sunk CAPEX decision no one revisited. In the cloud, it is an OPEX leak on every invoice.</p><h3><strong>2. Storage class drift</strong></h3><p>Lift&#8209;and&#8209;shift tooling defaults to &#8220;safe&#8221; storage tiers: GP2/GP3 volumes, standard [internal], general&#8209;purpose everything.</p><ul><li><p>Backups, logs, and archives land on the most expensive reasonable tier.</p></li><li><p>Nobody circles back to reclassify them because &#8220;optimize storage&#8221; loses to &#8220;migrate the next wave.&#8221;</p></li></ul><p>Cold data keeps paying hot&#8209;data rates indefinitely.</p><h3><strong>3. Data transfer that never existed as a line item before</strong></h3><p>On&#8209;prem, traffic between app, DB, and dependencies rides the LAN for free.</p><p>In cloud, the same paths can cross:</p><ul><li><p>AZ boundaries</p></li><li><p>Region boundaries</p></li><li><p>Out to the internet</p></li></ul><p>Each with its own per&#8209;GB charge that had <strong><span>no equivalent</span></strong> on the data center bill. It never showed up in the baseline, so it never made it into the model.</p><p>All three problems come from modeling what the workload is <strong><span>provisioned for</span></strong> instead of what it actually <strong><span>does</span></strong>.</p><div><hr></div><h2><strong>The Three Questions That Catch This Before Cutover</strong></h2><p>Rehost is still the fastest, lowest&#8209;risk way to move a big portfolio.</p><p>These three questions decide whether it&#8217;s also a <strong><span>cost win</span></strong>. They need answers <strong><span>before</span></strong> the business case is signed, not after the first invoice lands.</p><h3><strong>1. What does this workload actually use, not what is it provisioned for?</strong></h3><p>Pull real utilization:</p><ul><li><p>CPU, memory, disk, IOPS</p></li><li><p>Over a window that includes representative peaks</p></li></ul><p>Size instances to that pattern, with buffer, instead of mirroring the old server spec.</p><p>This single change closes most of the gap on most rehosts.</p><h3><strong>2. What is the access pattern for every dataset this workload touches?</strong></h3><p>Classify data by access:</p><ul><li><p>Hot: request path, low&#8209;latency, high&#8209;frequency</p></li><li><p>Warm: regular but not critical</p></li><li><p>Cold: backups, logs, archives, legal holds</p></li></ul><p>Each class has a different cost&#8209;optimal storage tier. Your model should have <strong><span>per&#8209;dataset</span></strong> storage assumptions, not one blended number.</p><p>Defaulting everything to a single &#8220;safe&#8221; tier is how storage quietly eats the savings.</p><h3><strong>3. What does this workload talk to, and where do those calls cross billable boundaries?</strong></h3><p>Map dependencies:</p><ul><li><p>Databases, caches, downstream services, third&#8209;party APIs</p></li><li><p>Which connections stay inside an AZ vs. cross-AZ / region / internet?</p></li></ul><p>This is the line item that has <strong><span>no on&#8209;prem analog</span></strong>, which is exactly why it&#8217;s the one most often skipped.</p><p>Once you see the paths, you can:</p><ul><li><p>Co&#8209;locate chatty services</p></li><li><p>Avoid unnecessary cross&#8209;region calls</p></li><li><p>Decide consciously where to pay for egress</p></li></ul><p>Answer these three and you&#8217;ve turned the &#8220;savings&#8221; slide from a wish into a forecast.</p><p>A forecast is the only thing finance should be signing off on.</p><div><hr></div><h2><strong>What a Rehost Looks Like When the Math Holds</strong></h2><p>When you model these three line items up front, the rehost does what the slide deck promised.</p><ul><li><p>Right&#8209;sized instances mean you pay for actual consumption, not inherited overprovisioning.</p></li><li><p>Correct storage tiering means cold data costs cold&#8209;data rates.</p></li><li><p>Pre&#8209;mapped data transfer means you can design away the worst egress paths <em>before</em> they start billing.</p></li></ul><p>The first finance review after cutover becomes validation, not a surprise.</p><p>And that changes the trajectory of the entire program:</p><ul><li><p>Wave 1 shows invoices that match the model.</p></li><li><p>Wave 2 budget gets approved off <strong><span>evidence</span></strong>, not optimism.</p></li><li><p>The conversation shifts from &#8220;Can we trust these numbers?&#8221; to &#8220;How fast can we scale the factory?&#8221;</p></li></ul><p>That is the real payoff: a migration program that can point at real bills and say, &#8220;The math holds.&#8221;</p><div><hr></div><p><em><strong>Free tool: Score your AWS platform&#8217;s predictability in 5 minutes</strong><br>If this hit close to home, you probably have other places where ownership and accountability are fuzzy but invisible until something breaks.</em></p><p><em>To make this practical, I put together a free <strong>AWS Platform Predictability Starter Kit</strong> for readers:</em></p><ul><li><p><em>5&#8209;minute predictability checklist</em></p></li><li><p><em>&#8220;Where are we bleeding?&#8221; team scorecard</em></p></li><li><p><em>Platform risk radar with 12 early&#8209;warning signals</em></p></li><li><p><em>10 executive questions with weak vs strong answers + debrief worksheet<br>Most leaders run through these in a week of normal meetings and come away with a clear &#8220;top 3&#8221; to fix next.</em></p></li></ul><p><em>&#128073; Grab the free PDF here: <a href="https://thecloudplaybook.gumroad.com/l/aws-platform-predictability-check">https://thecloudplaybook.gumroad.com/l/aws-platform-predictability-check</a></em></p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #137: The migration strategy meeting that never needed to be a meeting.]]></title><description><![CDATA[Four questions that sort any workload into rehost, replatform, refactor, repurchase, retain, or retire, before the debate starts.]]></description><link>https://www.thecloudplaybook.com/p/6-rs-migration-decision-tree-aws</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/6-rs-migration-decision-tree-aws</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sat, 01 Aug 2026 14:41:51 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!xErF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every migration program hits the same wall.</p><p>Someone opens the workload inventory, points at application one, and asks: <span>rehost, replatform, or refactor?</span></p><p>The room debates for forty minutes. They land on an answer.</p><p>Then they point at application two, and the debate starts over, because nobody wrote down <em>why</em> they chose what they chose for application one.</p><p>Multiply that by 200 applications, and you get a migration program that spends its first quarter in conference rooms instead of moving workloads.</p><p>The strategy debate is not the hard part of migration.</p><p>It only feels that way because most teams run it as an open discussion instead of a decision tree.</p><p>The 6 R&#8217;s (rehost, replatform, refactor, repurchase, retain, retire) are not opinions to argue per workload.</p><p>They&#8217;re the output of four questions, asked in a fixed order.</p><p>Skip the order, and you get the meeting that repeats itself 200 times.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xErF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xErF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!xErF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!xErF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!xErF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!xErF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1452037,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/208511031?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xErF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!xErF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!xErF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!xErF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a55d719-1a25-43e6-b7ab-055a5d383b05_1448x1086.png 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Why the Wrong R Costs More Than the Migration</h2><p>Picking the wrong strategy rarely fails loudly. It fails as a slow leak you notice two quarters later.</p><p>Refactor a workload that should have been a simple rehost, and you&#8217;ve spent six months of senior engineering time re&#8209;architecting an application nobody asked to modernize. Meanwhile, the business misses a data center exit you could have hit with a lift&#8209;and&#8209;shift.</p><p>Rehost a workload that should have been retired, and you&#8217;ve paid to move an app three people still use. Once it&#8217;s &#8220;already migrated,&#8221; nobody revisits it. You&#8217;ve made a zombie workload immortal.</p><p>The cost isn&#8217;t just engineering time. It&#8217;s <span>factory throughput</span>.</p><ul><li><p>A factory tuned for rehost velocity chokes on refactor&#8209;sized workloads.</p></li><li><p>A factory that treats everything as bespoke refactor never hits the wave&#8209;based timelines the business signed up for.</p></li></ul><p>Wrong R&#8217;s compound:</p><ul><li><p>Your best engineers get stuck on work that didn&#8217;t need them.</p></li><li><p>The workloads that <em>do</em> need refactor never get the attention or budget.</p></li></ul><p>Migration budgets are approved once, based on an assumed strategy mix. When the mix is wrong, the budget doesn&#8217;t stretch. It just runs out before the portfolio is done.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Why Smart Teams Default to Refactor or Rehost</h2><p>Two patterns explain most bad decisions. Both come from forcing a whole portfolio through one mental model.</p><ol><li><p><strong><span>Modernization bias</span></strong><br>Architects who care about &#8220;doing it right&#8221; default to refactor, because that&#8217;s where the interesting engineering lives. A stable, low&#8209;change, &#8220;good enough&#8221; app still gets nominated for re&#8209;architecture, not because the business needs it, but because it&#8217;s more satisfying than rehosting.</p></li><li><p><strong><span>Deadline bias</span></strong><br>Teams under a hard exit deadline default everything to rehost because it&#8217;s fast and predictable. Workloads that genuinely <em>need</em> refactoring get lifted and shifted in their brittle state, now with cloud spend on top of the technical debt.</p></li></ol><p>Both biases share a root cause: strategy is being chosen from one vantage point (architect or program manager), not from the four questions that actually govern the right R.</p><div><hr></div><h2>The Four Questions That Sort Any Workload</h2><p>Ask these in order. The order matters. Each question eliminates options before the next one.</p><p><strong><span>1. Does the business still need this workload?</span></strong><br>If usage is near zero, or it exists only because no one decommissioned it, <span>retire</span> beats every other option.</p><p>This comes first because retirement is the only R that shrinks your migration backlog. Every workload retired here is one the factory never touches.</p><p><strong><span>2. Is there a commercial replacement that does this better?</span></strong><br>If the workload is a homegrown system duplicating what a SaaS or managed product already does, <span>repurchase</span> often beats refactor or rehost.</p><p>This comes second because it can eliminate big, hairy workloads before you burn cycles estimating them.</p><p><strong><span>3. Does it need to change, or just move?</span></strong><br>If requirements, performance, and architecture are &#8220;good enough,&#8221; <span>rehost or replatform</span> gets you to cloud fastest.</p><ul><li><p>Rehost: move as&#8209;is when change doesn&#8217;t pay for itself.</p></li><li><p>Replatform: swap obvious managed services (e.g., self&#8209;managed DB to RDS) when the operational savings justify it.</p></li></ul><p>If there&#8217;s a real business reason to change (scalability limiting revenue, licensing that dies in cloud, compliance gaps), that&#8217;s the signal for <span>refactor</span>.</p><p><strong><span>4. Does the deadline allow the strategy this workload actually needs?</span></strong><br>This is a check, not a chooser.</p><p>If 1&#8211;3 say &#8220;refactor&#8221; and the data center exit is in 12 weeks, that conflict gets escalated. The business chooses: move the deadline or consciously downgrade the strategy.</p><p>Do <span>not</span> let the schedule silently pick a lesser strategy and pretend nothing changed.</p><p>Run every workload through these four and the R mostly picks itself. The 40&#8209;minute debate collapses to four questions, many of which your CMDB already answers.</p><div><hr></div><h2>What a Portfolio Run Through This Tree Looks Like</h2><p>Programs that apply these four questions consistently get a <span>strategy mix</span>, not a never&#8209;ending strategy debate.</p><p>That mix is what the migration factory needs to:</p><ul><li><p>Plan capacity</p></li><li><p>Sequence waves</p></li><li><p>Forecast cost and timelines</p></li></ul><p>What changes:</p><ul><li><p><span>Retire and repurchase</span> decisions happen <em>before</em> wave planning, shrinking the portfolio.</p></li><li><p><span>Rehost and replatform</span> carry most of the volume on a predictable, assembly&#8209;line cadence.</p></li><li><p><span>Refactor</span> is reserved for the few workloads where the business case genuinely justifies it, staffed with the senior engineers who should be there.</p></li></ul><p>The visible outcome:</p><ul><li><p>Portfolio reviews that used to run for weeks compress into days.</p></li><li><p>Strategy per workload becomes a <span>lookup</span>, not a debate.</p></li><li><p>Engineering time that used to be spent re&#8209;litigating strategy goes into moving workloads.</p></li></ul><p>That&#8217;s the leadership payoff: not a cuter framework, but a portfolio that stops arguing with itself and starts moving.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP#136: You picked your secret store by cost. That was the wrong axis.]]></title><description><![CDATA[Secrets Manager vs. Parameter Store vs. KMS-encrypted env on AWS: a decision matrix. Why teams pick the wrong secret store by cost or habit, and the axes that produce a defensible choice per secret.]]></description><link>https://www.thecloudplaybook.com/p/secrets-manager-vs-parameter-store-aws</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/secrets-manager-vs-parameter-store-aws</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 26 Jul 2026 14:43:48 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Mwib!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most teams choose a secret store the same way they choose a compute platform: by preference or cost, not by what the secret actually needs.</p><p>One team saw Secrets Manager&#8217;s per&#8209;secret pricing, decided it was expensive, and standardized on Parameter Store for everything. Another standardized on Secrets Manager because it sounded &#8220;purpose&#8209;built.&#8221; A third never decided at all:</p><ul><li><p>Database passwords in SSM parameters</p></li><li><p>API keys in Secrets Manager</p></li><li><p>A few credentials in KMS&#8209;encrypted env vars because that was fastest for one service two years ago</p></li></ul><p>Different routes, same destination: secrets live where habit or a cost comparison put them, not where the secret&#8217;s requirements put them.</p><p>And those requirements differ: a rotating database password is not the same as a static third&#8209;party API key, which is not the same as a config value that&#8217;s merely sensitive.</p><p>Optimizing for the cheapest monthly line item while ignoring rotation, audit, and incident response is optimizing the wrong variable.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Mwib!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Mwib!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!Mwib!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!Mwib!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!Mwib!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Mwib!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1559095,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/208409166?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Mwib!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!Mwib!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!Mwib!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!Mwib!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14322c40-af7d-41ea-9db7-0893585ad472_1448x1086.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3>Why the Wrong Store Is a Real Cost</h3><p>A secret in the wrong store is not a billing issue. It is:</p><ul><li><p>A <span>rotation problem</span></p></li><li><p>An <span>audit problem</span></p></li><li><p>An <span>incident&#8209;response problem</span> waiting for its moment</p></li></ul><p><strong><span>Rotation cost:</span></strong><br>A database credential in plain Parameter Store does not rotate itself. Someone has to remember. They don&#8217;t. A credential that should live 30 days lives 2 years. When it leaks, the blast radius is 2 years of access, not 30 days.</p><p><strong><span>Audit cost:</span></strong><br>Compliance frameworks want proof: scheduled rotation, scoped access, logged reads. A secret in the wrong store cannot show that history. The auditor asks for rotation records, and there are none, because that store doesn&#8217;t rotate.</p><p><strong><span>Incident cost:</span></strong><br>When a credential leaks, the first questions are:</p><ul><li><p>How old is it?</p></li><li><p>What can it reach?</p></li><li><p>How fast can we rotate or revoke it?</p></li></ul><p>The store built for rotation answers quickly. The store chosen for price does not, and the incident stretches from hours into days.</p><p>The monthly price delta between stores is small.<br>The cost of a credential you cannot rotate, audit, or quickly revoke is very high, and shows up exactly when you can least afford it.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Cloud Playbook! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h3>How Teams End Up With Secrets Scattered</h3><p>Sprawl is not usually a decision. It&#8217;s the absence of one.</p><ul><li><p>The first secret goes &#8220;wherever&#8221; because one engineer had to ship one service.</p></li><li><p>The second secret goes somewhere else because another engineer made a different local call.</p></li><li><p>Neither choice is crazy in isolation. Together, they are the start of chaos.</p></li></ul><p>Then cost anxiety accelerates it:</p><ul><li><p>Secrets Manager&#8217;s per&#8209;secret line is visible on the bill</p></li><li><p>Parameter Store&#8217;s usage is fuzzier</p></li><li><p>A cost review flags Secrets Manager</p></li><li><p>The team moves secrets to the &#8220;cheaper&#8221; store without checking whether it meets the secrets&#8217; requirements</p></li></ul><p>The bill goes down. Rotation and audit capability go with it.</p><p>This persists because <span>nobody owns the decision</span>. There&#8217;s a standard for compute, a standard for networking, and no standard for secrets. So the question &#8220;where does this go?&#8221; gets answered per engineer, per service, per deadline.</p><p>Sprawl is the predictable result of a decision nobody was assigned to make.</p><div><hr></div><h3>The Axes That Actually Decide</h3><p>The &#8220;right&#8221; store is not about preference or price. It&#8217;s about four properties of the secret itself. Score the secret on these, and the store largely selects itself.</p><ol><li><p><span>Does it need automatic rotation?</span><br>This is the first cut.</p><ul><li><p>Must&#8209;rotate (e.g. most DB credentials, many service credentials) &#8594; Secrets Manager, with native rotation where possible</p></li><li><p>Does&#8209;not&#8209;rotate (static third&#8209;party key, certain config values) &#8594; does not need to pay for rotation it won&#8217;t use</p></li></ul></li><li><p><span>How sensitive is it and what&#8217;s the blast radius if it leaks?</span></p><ul><li><p>High&#8209;blast&#8209;radius (prod DB with customer data) &#8594; strongest access controls, logging, and rotation</p></li><li><p>Lower sensitivity (non&#8209;public but low&#8209;impact config) &#8594; can live in a simpler store</p></li></ul></li><li><p><span>How often is it read, and by what?</span><br>Read pattern affects both architecture and cost:</p><ul><li><p>Read on every request by a high&#8209;traffic service &#8594; needs caching and cost awareness</p></li><li><p>Read once at startup &#8594; throughput less relevant</p></li></ul><p>Parameter Store and Secrets Manager behave differently under load; the wrong choice here is either a latency issue or a surprise bill.</p></li><li><p><span>What&#8217;s its compliance scope?</span><br>In&#8209;scope for FedRAMP / HIPAA / ISO? Then you may be forced into:</p><ul><li><p>Demonstrable rotation</p></li><li><p>Scoped IAM</p></li><li><p>Auditable access history</p></li></ul><p>&#8220;We cannot demonstrate rotation&#8221; is a finding all by itself.</p></li></ol><p><span>KMS&#8209;encrypted environment variables</span> sit at the bottom of this matrix on purpose. They are right for a narrow case:</p><ul><li><p>Value needed only at process start</p></li><li><p>Not sensitive enough to justify a lookup per read</p></li><li><p>Does not rotate</p></li></ul><p>They are wrong for almost everything else. When secrets land here, it&#8217;s because no one applied the matrix at all.</p><div><hr></div><h3>What a Standard Changes</h3><p>Teams that define <span>where each class of secret belongs</span> stop putting secrets in the wrong place.</p><ul><li><p>Rotating database credentials live where rotation is native, so they actually rotate, and a leak&#8217;s blast radius is 30 days, not 2 years.</p></li><li><p>Static API keys live where they aren&#8217;t paying for rotation they don&#8217;t need.</p></li><li><p>High&#8209;sensitivity secrets live where access is tightly scoped and logged, so audits pull reports instead of doing archaeology.</p></li><li><p>Low&#8209;risk config values live in the simple store, so the expensive store is reserved for secrets that justify it.</p></li></ul><p>When a credential leaks, the response is fast because the store was chosen for that risk class. The team knows its age, reach, and rotation path because the store was designed to answer those questions.</p><p>Secrets stop being scattered by accident and start being placed by design. The store follows the secret&#8217;s requirements, and the requirements were explicitly examined instead of assumed.</p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #135: The GuardDuty org-wide gotchas that break your Terraform run]]></title><description><![CDATA[Delegated admin, per-feature enablement, severity routing, and the multi-region and provider traps, all as code]]></description><link>https://www.thecloudplaybook.com/p/guardduty-org-wide-terraform-aws</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/guardduty-org-wide-terraform-aws</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Thu, 23 Jul 2026 15:07:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!CrYV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You decided to enable GuardDuty org&#8209;wide as code. Good. Now you&#8217;re going to hit the gotchas that the console hides, but Terraform does not.</p><p>The console&#8217;s org&#8209;wide enablement is a smooth process because AWS paper-overs the underlying complexity. Terraform does not. When you enable GuardDuty across an organization with Terraform, you run into reality:</p><ul><li><p>GuardDuty is regional</p></li><li><p>Delegated administration has strict ordering</p></li><li><p>Auto&#8209;enable behaves differently for existing vs new accounts</p></li><li><p>Member association is not the same as feature enablement</p></li></ul><p>Teams that don&#8217;t know this up front get a rollout that half&#8209;works:</p><ul><li><p>GuardDuty on in one region, missing in three</p></li><li><p>New accounts get it, existing ones don&#8217;t (or the reverse)</p></li><li><p>Delegated administrator set, member accounts not associated</p></li></ul><p>Every one of these is a coverage gap that appears to be a success in the one dashboard you happen to be staring at.</p><p>This issue is the map of those gotchas and the code structure that avoids them.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CrYV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CrYV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!CrYV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!CrYV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!CrYV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CrYV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1473750,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/207499651?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CrYV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!CrYV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!CrYV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!CrYV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b5947-1c3a-4bc0-8ab1-007927a02c39_1448x1086.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Why the Gotchas Are Expensive</h2><p>A half&#8209;enabled detection system is more dangerous than an un&#8209;enabled one, because it creates false confidence.</p><p>The team believes GuardDuty is running org&#8209;wide. The audit evidence says it is enabled. But coverage has holes:</p><ul><li><p>A region never turned on</p></li><li><p>Accounts that predate the auto&#8209;enable setting</p></li><li><p>A feature enabled in the delegated administrator but never propagated</p></li></ul><p>The threat that lands in one of those holes is undetected, and nobody knows the hole exists until an incident review finds it. Discovering it after the fact means a multi&#8209;week backfill project instead of a plan and an apply.</p><p>The gotchas are cheap to handle before rollout and expensive after. Doing this as code only pays off if the code encodes the handling so the gaps never open.</p><h2>How the Gaps Open</h2><p>These coverage gaps are not due to carelessness. They are the predictable result of GuardDuty&#8217;s architecture meeting an org&#8209;wide rollout.</p><ul><li><p><strong><span>Regional service.</span></strong> GuardDuty is regional. Enabling it is a per&#8209;region action. Teams think in terms of &#8220;the organization,&#8221; focus on accounts, and then cover only their primary region while silently omitting the others.</p></li><li><p><strong><span>Auto&#8209;enable subtlety.</span></strong> Auto&#8209;enable controls whether <strong><span>new</span></strong> member accounts are enabled for GuardDuty. It does not retroactively turn it on for existing accounts. Teams that set auto&#8209;enable and assume full coverage miss every pre&#8209;existing account.</p></li><li><p><strong><span>Feature enablement vs association.</span></strong> Associating a member account with the delegated admin brings findings into view. It does not automatically enable additional protection features. Teams that associate all accounts and assume malware protection is on have coverage associated with accounts, not feature coverage.</p></li></ul><p>The console flow hides most of this. Terraform surfaces it. That&#8217;s a feature, not a bug: the code forces explicit decisions, and explicit decisions do not turn into silent gaps.</p><h2>The Decision Framework and the Gotchas</h2><p>Structuring Terraform correctly requires resolving four things. Each has a gotcha.</p>
      <p>
          <a href="https://www.thecloudplaybook.com/p/guardduty-org-wide-terraform-aws">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TCP #134: GuardDuty org-wide is a one-click decision with a six-month tail.]]></title><description><![CDATA[The pre-flight decisions on delegated admin, cost, and alert routing that decide whether GuardDuty becomes signal or noise.]]></description><link>https://www.thecloudplaybook.com/p/guardduty-preflight-org-wide-aws</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/guardduty-preflight-org-wide-aws</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 19 Jul 2026 14:29:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BWPk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong><span>Enabling GuardDuty across your organization takes just a few clicks. Making it useful is not.</span></strong></p><p>Most teams do the same thing:</p><ul><li><p>Someone in the security account enables GuardDuty</p></li><li><p>Delegated admin is set</p></li><li><p>Auto&#8209;enable is turned on for all member accounts</p></li></ul><p>Now the estate has threat detection &#8220;everywhere.&#8221; The dashboard fills with findings. Everyone feels safer.</p><p>Six months later, those findings land in an inbox nobody reads. The volume is high, the severity is mixed, and nobody has decided who acts on what.</p><p>GuardDuty is generating thousands of dollars <span>in value from&nbsp;</span><em><span>detection</span></em><span>&nbsp;and zero dollars in value from</span> <em>response</em>, because the response side was never designed.</p><p>GuardDuty is not the failure. GuardDuty works.<br>The failure is enabling a detection system without first deciding what happens when it detects something.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BWPk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BWPk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!BWPk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!BWPk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!BWPk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BWPk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1424922,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/207499125?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BWPk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!BWPk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!BWPk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!BWPk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4913c4d3-244a-48df-a9c4-3e02f25d049a_1448x1086.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Why the &#8220;Enable&#8221; Click Has a Long Tail</h2><p>GuardDuty is easy to turn on and expensive to turn on incorrectly. The expense is delayed enough that the connection is easy to miss.</p><p>You pay in two currencies:</p><p><strong><span>1. Dollars</span></strong></p><p>GuardDuty pricing scales with the volume of events it analyzes. Volume&#8209;heavy sources like:</p><ul><li><p>S3 data events</p></li><li><p>EKS audit logs</p></li><li><p>Malware protection</p></li><li><p>RDS protection</p></li></ul><p>Can multiply the bill in ways that surprise teams who enabled everything by default. An org&#8209;wide enablement with every feature on, across a large estate, can produce a monthly bill that triggers a finance conversation nobody planned for.</p><p><strong><span>2. Attention (the more damaging one)</span></strong></p><p>A detection system that produces more findings than the team can triage trains the team to ignore them.</p><p>The high&#8209;severity finding that matters arrives in the same flood as hundreds of low&#8209;severity informational findings, and it gets missed.</p><p>An ignored detection system is worse than no detection system because it creates the appearance of coverage without the substance.</p><p>Both costs are set by decisions made <em>before</em> the enable, not after. That makes this a pre&#8209;flight problem.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Cloud Playbook is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>How Good Teams Still Enable It Wrong</h2><p>The wrong&#8209;way enable is not negligence. It&#8217;s a reasonable response to how the feature presents itself.</p><p>GuardDuty&#8217;s setup flow makes the easy path the default path:</p><ul><li><p>Enable</p></li><li><p>Delegate</p></li><li><p>Auto&#8209;enable for all accounts</p></li><li><p>Done</p></li></ul><p>The flow does <strong><span>not</span></strong> ask:</p><ul><li><p>Who will read the findings?</p></li><li><p>What will this cost at your current event volume?</p></li><li><p>How does a critical finding reach a human with a pager?</p></li></ul><p>It just turns detection on, and that <em>feels</em> like the responsible thing to do.</p><p>Security teams are under pressure to show coverage.</p><p>&#8220;Is GuardDuty enabled?&#8221; is a question for an auditor and a customer.<br>The fastest way to answer &#8220;yes&#8221; is the one&#8209;click org&#8209;wide enable.</p><p>The box measures whether detection is on, not whether the response works.</p><p>So detection gets enabled comprehensively, and response is never designed. Findings accumulate. Volume becomes noise. The team that enabled a security control to reduce risk has added an alerting channel that everyone learns to mute.</p><p>The gap between &#8220;enabled&#8221; and &#8220;operational&#8221; is invisible until an incident falls into it.</p><div><hr></div><h2>Four Decisions to Make <em>Before</em> You Enable Org&#8209;Wide</h2><p>GuardDuty org&#8209;wide <em>is</em> worth doing. It&#8217;s worth doing <strong><span>after</span></strong> four decisions, not before.</p><p>Each one determines whether the system produces a signal or noise.</p><h3>1. Who is the delegated administrator?</h3><p>GuardDuty findings from every member account aggregate to a delegated administrator account.</p><p>That should be your <strong><span>security account</span></strong>, not the management account:</p><ul><li><p>Security tooling lives where the security team operates</p></li><li><p>The management account stays minimal and boring</p></li></ul><p>Choosing the wrong one is painful to reverse once findings are flowing.</p><h3>2. What will each feature cost at your scale?</h3><p>Foundational GuardDuty is one cost. The add&#8209;ons are separate:</p><ul><li><p>S3 protection</p></li><li><p>EKS audit log monitoring</p></li><li><p>Malware protection</p></li><li><p>RDS protection</p></li></ul><p>Each scale with your actual usage patterns.</p><p>Before enabling, estimate:</p><ul><li><p>Monthly cost <em>per feature</em></p></li><li><p>Against <em>your</em> current log and data volumes</p></li></ul><p>Then enable the features whose value justifies their cost. Not &#8220;all of them because they&#8217;re available.&#8221;</p><h3>3. Where do findings go, and who owns each severity?</h3><p>This is the decision that separates signal from noise.</p><p>Design this explicitly:</p><ul><li><p><strong><span>High</span></strong>: pages a human (on&#8209;call rotation/incident channel)</p></li><li><p><strong><span>Medium</span></strong>: goes to a queue where someone actually works (ticket system, triage channel)</p></li><li><p><strong><span>Low / Informational</span></strong>: logged for forensic use, not alerted</p></li></ul><p>Without this routing, every finding goes to the same destination with the same urgency. The important ones drown.</p><h3>4. What is your plan for the initial flood?</h3><p>The moment you enable GuardDuty org&#8209;wide, it surfaces findings for existing conditions. The first days produce a backlog, not a steady state.</p><p>Decide in advance:</p><ul><li><p>Who owns triage for the initial flood</p></li><li><p>How you&#8217;ll distinguish pre&#8209;existing conditions from new threats</p></li><li><p>Which classes of &#8220;old but still present&#8221; findings will trigger immediate work vs backlog remediation</p></li></ul><p>That keeps the launch from overwhelming the team on day one.</p><p><br>Enabling detection is a five&#8209;minute decision. Designing a response is the actual work.<br>Do the actual work first.</p><p>A detection system is only as valuable as the response it triggers.</p><div><hr></div><h2><strong>What Changes When Response Is Designed First</strong></h2><p>Teams that make these decisions <em>before</em> enabling get a security control that works, not a dashboard that decorates.</p><ul><li><p>Findings are routed by severity: critical ones go to a human, and informational ones go to a log.</p></li><li><p>The team trusts alerts because alerts are calibrated, and trusted alerts are acted on.</p></li><li><p>The monthly bill is a number someone chose, not a surprise that escalates.</p></li></ul><p>When an auditor asks about threat detection, the answer isn&#8217;t just &#8220;it&#8217;s enabled.&#8221;</p><p>The answer is: &#8220;It&#8217;s enabled, findings route to these owners at these severities, and here is our mean time to acknowledge a high&#8209;severity finding.&#8221;</p><p>That&#8217;s the difference between a checkbox and a capability.</p><p>GuardDuty stops being a system that generates findings nobody reads and becomes a system that generates responses that contain threats.</p><p>Detection was always the easy part.<br>Designing the response <em>before</em> you click enable is what makes the detection matter.</p><div><hr></div><h2>Coming Wednesday for paid subscribers</h2><p>On Wednesday, paid subscribers get the full system for enabling GuardDuty org&#8209;wide with Terraform, including the gotchas:</p><ul><li><p>Delegated administrator setup</p></li><li><p>Per&#8209;feature enablement decisions encoded as code</p></li><li><p>Severity&#8209;based routing and alerting design</p></li><li><p>Initial&#8209;flood triage plan</p></li><li><p>The Terraform and org&#8209;structure edge cases that break an org&#8209;wide enable</p></li></ul><p>If you want GuardDuty to be a control your team <em>runs</em>, not a dashboard you ignore, that&#8217;s the operating model.</p><div><hr></div><h3>Upgrade If You Need Implementation, Not Just Ideas</h3><p>If you&#8217;re using these emails to guide real decisions on your platform, you&#8217;ll get more leverage from the paid version of The Cloud Playbook.</p><p>The free newsletter gives you patterns and language.</p><p>The paid newsletter turns those patterns into implementation kits you can ship inside a quarter:</p><ul><li><p>Concrete rollout plans (90&#8209;day roadmaps for each pattern)</p></li><li><p>Templates and checklists (policies, runbooks, tagging schemes, review checklists)</p></li><li><p>Real examples from high&#8209;stakes AWS environments (what we actually shipped and why)</p></li></ul><p>If the paid side doesn&#8217;t save you more than the subscription in <strong>one</strong> incident, audit cycle, or bad migration you avoid, you should cancel and keep the playbooks.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe&quot;,&quot;text&quot;:&quot;Upgrade to the Paid Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.thecloudplaybook.com/subscribe"><span>Upgrade to the Paid Cloud Playbook</span></a></p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #133: Permission sets belong in a pipeline, not in the Identity Center console]]></title><description><![CDATA[The controls-as-code system for permission sets: repo structure, CI/CD deployment, privilege review gates, and drift detection]]></description><link>https://www.thecloudplaybook.com/p/iam-identity-center-permission-sets-as-code</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/iam-identity-center-permission-sets-as-code</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Thu, 16 Jul 2026 15:02:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rYsZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You centralized identity. IAM Identity Center is your source of truth. Human access runs through federation, not static keys. That was the hard part, and you did it.</p><p>Then someone widened a permission set in the console during an incident, and nobody knows.</p><p>The permission set, which was scoped to read-only, now has write access because an engineer needed it at 2 a.m., and the console was right there. The change is live in every account to which the permission set is assigned. There is no pull request, no reviewer, no record of why. The access review three months from now will find it, or it will not.</p><p>Centralizing identity solved the problem of credential sprawl. It did not solve the sprawl of permissions inside the centralized system.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rYsZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rYsZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!rYsZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!rYsZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!rYsZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rYsZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1478943,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/206649627?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rYsZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!rYsZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!rYsZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!rYsZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4e06a94-cc58-456f-8b53-00294b0afda8_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Why Console-Edited Permission Sets Undo the Work</h2><p>The value of IAM Identity Center lies in the fact that access is defined in one place. That value evaporates the moment the one place is edited by hand.</p><p>A permission set is not a small object. It is a bundle of policies that applies to potentially dozens of accounts at once. A single console edit to a widely assigned permission set is one of the highest-blast-radius changes available in your entire AWS estate, and it is available to anyone with console access to the management account.</p><p>The cost is the same as that of any unversioned control. At audit time, you cannot show the history of who changed what and why. During an incident, you cannot tell whether a permission set is in its intended state or in the state someone left it months ago. And the privilege-escalation review that your compliance framework requires becomes impossible, because the thing you are reviewing changes underneath you without a trace.</p><p>You did the work to centralize. Managing permission sets by hand quietly gives it back.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Cloud Playbook is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>How Teams Backslide After Centralizing</h2><p>The backslide is not a decision. It is the path of least resistance reasserting itself.</p>
      <p>
          <a href="https://www.thecloudplaybook.com/p/iam-identity-center-permission-sets-as-code">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TCP #132: Your Control Tower guardrails belong in Terraform, not the console]]></title><description><![CDATA[The controls-as-code system for preventive, detective, and proactive guardrails, with review, drift detection, and rollout order.]]></description><link>https://www.thecloudplaybook.com/p/control-tower-controls-as-code-terraform</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/control-tower-controls-as-code-terraform</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 12 Jul 2026 14:25:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!PhQW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most teams enable Control Tower controls by clicking through the console.</p><p>Someone enables a guardrail during setup. Someone else enables three more during an audit scramble. A year later, the landing zone has 40 controls applied across five OUs, and no one can tell you why any single control is on, who turned it on, or what breaks if it comes off.</p><p>The controls work. They deny the actions they are supposed to deny. But the configuration lives in the console, not in a repository, and that means it cannot be reviewed, diffed, rolled back, or reasoned about as a system.</p><p>This is the gap between having guardrails and operating them.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PhQW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PhQW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!PhQW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!PhQW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!PhQW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PhQW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1516912,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/206648884?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PhQW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!PhQW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!PhQW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!PhQW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5e520ec-d597-4163-afdc-1fb472df984f_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Why Console-Managed Controls Become a Liability</h2><p>Control Tower controls are the enforcement layer of your landing zone. They are also, for most teams, the least version-controlled part of the entire AWS estate.</p><p>The cost shows up at audit time. An auditor asks which controls enforce a given SOC 2 requirement, and the team produces a screenshot instead of a commit. The evidence is a point-in-time snapshot with no history, no author, and no justification.</p><p>The cost also shows up during incidents. A deploy fails because a proactive control blocks it. The engineer does not know the control exists, cannot find where it is configured, and cannot tell whether disabling it is safe. The control meant to prevent a mistake now causes an outage in developer velocity instead.</p><p>Controls managed by clicking are controls that drift. Someone disables one to unblock a launch and never re-enables it. The guardrail that your compliance posture depends on is now off, and nothing in your system knows.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Cloud Playbook is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>How Smart Teams End Up Here</h2><p>No one decides to manage controls by hand. The console path is simply the fastest way to unblock the immediate need.</p><p>Control Tower&#8217;s own interface encourages it. The landing zone is set up through the console, so the first controls are enabled there. The pattern is set before anyone asks whether it should be code.</p><p>Then the team scales. More OUs, more accounts, more frameworks in scope. Each new requirement adds controls, and each addition happens where the last one did: in the console, under deadline, by whoever is closest to the problem.</p><p>The team that would never deploy a Lambda function without a repository is managing the enforcement layer of its entire compliance posture with mouse clicks. The inconsistency is invisible because controls feel like configuration rather than infrastructure. They are infrastructure. They deny real actions in real accounts, and they belong under the same discipline as everything else you deploy.</p><h2>The Three Control Types and How to Manage Each</h2><p>Control Tower exposes three control types, and the controls-as-code decision varies by type.</p><ol><li><p><strong>Preventive controls</strong> are Service Control Policies. They stop an action before it happens: deny disabling CloudTrail, deny resource creation outside approved regions. These are the highest-value controls to manage as code because they are the ones an incident is most likely to touch. Manage them in Terraform against the OU, with the policy body in the repository so the exact denied actions are reviewable.</p></li><li><p><strong>Detective controls</strong> are AWS Config rules. They evaluate resources after creation and flag non-compliance, such as an S3 bucket without encryption or a security group with open ingress. Manage these as code so the rule set is consistent across all accounts, and so that a new framework requirement becomes a pull request, not a console session.</p></li><li><p><strong>Proactive controls</strong> are CloudFormation Guard hooks. They evaluate a resource before provisioning and block deployment if the evaluation fails. These are the controls most likely to surprise a developer, so managing them as code matters most for a different reason: the repository is where an engineer looks to understand why their deployment was blocked.</p></li></ol><p>The axis to weigh is the blast radius against reversibility. A preventive control at the org root has the widest blast radius and the slowest reversal. It gets the most reviews. A detective control in a single sandbox OU has a narrow blast radius and instant reversal. It gets less. Match the review weight to the control&#8217;s reach, and do not apply the same ceremony to every control regardless of consequence.</p><p>The second axis is framework mapping. Every control should trace to a named requirement. A control that enforces nothing anyone can name is a control that will eventually break a deploy for a reason no one can defend.</p><h2>Implementation Steps</h2><p>Deploy controls as code in this order. The sequence matters because early mistakes are the expensive ones.</p><ol><li><p><strong>Inventory the current state first.</strong> Before writing any Terraform, export every control currently enabled, the OU it targets, and its type. This is your baseline. You cannot manage as code what you have not first written down.</p></li><li><p><strong>Map each control to a requirement.</strong> For every control in the inventory, name the framework requirement or internal policy it enforces. Controls that map to nothing are candidates for removal, not import.</p></li><li><p><strong>Import, do not recreate.</strong> Bring existing controls into Terraform state using import blocks rather than destroying and recreating them. Recreating a preventive control means there is a window when the guardrail is off. Import avoids the gap.</p></li><li><p><strong>Structure the repository by OU and type.</strong> One module per OU, controls grouped by preventive, detective, and proactive. The structure should allow a reviewer to see all controls for a given OU in one place.</p></li><li><p><strong>Enforce review by blast radius.</strong> Controls at the org root or a production OU require a two-person review. Controls on a sandbox OU can ship with one. Encode this in the pull request rules, not in a wiki no one reads.</p></li><li><p><strong>Add drift detection.</strong> Run a scheduled plan against the control configuration. Any drift between the repository and the deployed state pages the owner. This is the check that catches the disabled-and-forgotten control before an auditor does.</p></li><li><p><strong>Stage rollout through OU progression.</strong> A new control lands on the sandbox OU first, then a non-production OU, then production. Never apply a new preventive control to the org root as its first deployment.</p></li></ol><h2>What to Measure</h2><p>Controls as code is a system, and the system should be measured.</p><ol><li><p><strong>Control coverage.</strong> The percentage of enabled controls that exist in the repository versus the console. Track this weekly during migration. The target is 100 percent, and anything managed in the console after migration is a regression.</p></li><li><p><strong>Drift events per month.</strong> The count of times the deployed control state diverged from the repository. A healthy landing zone trends toward zero. Persistent drift signals that someone is still editing controls by hand.</p></li><li><p><strong>Time-to-evidence for a control question.</strong> How long does it take to answer &#8220;which controls enforce this requirement&#8221; during an audit? With controls as code, this repository query takes minutes to run. An above-an-hour means the framework mapping is incomplete.</p></li></ol><p>Review these in the platform's monthly operating review. Coverage and drift are the two metrics that indicate whether the enforcement layer is under control.</p><h2>What Changes When Controls Are Code</h2><p>The landing zone stops being a black box.</p><p>Every guardrail has an author, a justification, and a history. The audit question that used to take a day of screenshotting becomes a repository search. The control that blocks a deploy is documented where the engineer already looks. The disabled-and-forgotten guardrail is caught by drift detection within a day, rather than surfacing at the next audit.</p><p>The enforcement layer of your compliance posture becomes a system you operate, not a configuration you hope is still correct.</p><div><hr></div><h3><strong>Upgrade If You Need Implementation, Not Just Ideas</strong></h3><p>If you&#8217;re using these emails to guide real decisions on your platform, you&#8217;ll get more leverage from the paid version of The Cloud Playbook.</p><p>The free newsletter gives you patterns and language.</p><p>The paid newsletter turns those patterns into implementation kits you can ship inside a quarter:</p><ul><li><p>Concrete rollout plans (90&#8209;day roadmaps for each pattern)</p></li><li><p>Templates and checklists (policies, runbooks, tagging schemes, review checklists)</p></li><li><p>Real examples from high&#8209;stakes AWS environments (what we actually shipped and why)</p></li></ul><p>If the paid side doesn&#8217;t save you more than the subscription in <strong>one</strong> incident, audit cycle, or bad migration you avoid, you should cancel and keep the playbooks.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe&quot;,&quot;text&quot;:&quot;Upgrade to the Paid Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.thecloudplaybook.com/subscribe"><span>Upgrade to the Paid Cloud Playbook</span></a></p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a reading topic, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #131: The multi-account checklist regulated SaaS teams should have written]]></title><description><![CDATA[Account strategy, identity, networking, tenancy, and audit &#8212; each section with owners, cadences, and evidence.]]></description><link>https://www.thecloudplaybook.com/p/aws-multi-account-design-checklist-saas</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/aws-multi-account-design-checklist-saas</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Thu, 09 Jul 2026 15:06:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!oiJ-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>AWS publishes excellent reference architectures for multi-account design. Most engineering teams have read them. Most engineering teams still ship multi-account environments that fail audits, leak access, or sprawl into operational debt.</p><p>The reference architectures are not wrong. They are incomplete in a specific way: they describe what the design looks like, not what the team commits to in order for the design to stay intact 18 months from now.</p><p>A checklist closes that gap. It explicitly names each design decision, the team that owns it, the verification cadence that prevents drift, and the artifact that proves the design is still in effect. The checklist does not produce a better design than the reference architecture. It produces a design that survives the conditions that erode reference architectures: org-chart changes, scope expansion, deadline pressure, and the silent drift that comes from boundaries without owners.</p><p>The checklist below is the one I would use with a regulated SaaS platform team. </p><p>It assumes SOC 2 Type II at a minimum, with a roadmap toward FedRAMP Moderate, HIPAA, or ISO 27001. The structure applies even if the team operates outside those frameworks; the cadences and evidence requirements are tighter for regulated workloads.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oiJ-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oiJ-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!oiJ-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!oiJ-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!oiJ-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oiJ-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1991753,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/205060366?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oiJ-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!oiJ-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!oiJ-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!oiJ-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff736cf3-9dff-4458-903c-0ce21a601019_1448x1086.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>How to Use the Checklist</h2><p>The checklist has seven sections. Each section contains design items, owners, verification cadences, and required artifacts.</p><p>For each item, the team commits to four things:</p>
      <p>
          <a href="https://www.thecloudplaybook.com/p/aws-multi-account-design-checklist-saas">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TCP #130: Multi-Account AWS Environments Fail When Nobody Owns the Boundaries]]></title><description><![CDATA[Why account sprawl, tenant separation, and shared services break down without explicit control-plane ownership.]]></description><link>https://www.thecloudplaybook.com/p/multi-account-aws-boundaries-ownership</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/multi-account-aws-boundaries-ownership</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 05 Jul 2026 14:28:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!WhFP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most engineering organizations adopted multi-account AWS for the right reasons.</p><p>The single-account deployment was sprawling. The blast radius was unacceptable. Compliance was difficult to scope. </p><p>The team split workloads across accounts: production, staging, and dev. Then a separate account for the data team. Then accounts for individual customer tenants. Then a logging account. Then a security tooling account.</p><p>By year three, the organization has 40 accounts. AWS Organizations holds the top of the tree. Control Tower, if the team adopts it, holds the bottom. The middle is unclear.</p><p>The accounts work. Workloads run in them. Bills are paid. But the boundaries between accounts, the rules about what crosses what and who decides, are owned by nobody.</p><p>When something goes wrong, the cost is visible. The data engineer cannot get cross-account access to the bucket they need. The compliance team cannot find the audit log for an action in the production account. The platform team discovers that three accounts have public S3 buckets nobody owns. The security team flags an IAM role assumption pattern that has been running for 14 months without review.</p><p>The accounts are not the problem. The boundaries between them are. And boundaries without owners produce the same outcomes as no boundaries at all.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WhFP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WhFP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!WhFP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!WhFP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!WhFP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WhFP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1502056,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/205055793?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WhFP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!WhFP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!WhFP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!WhFP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1f9ead6-108d-4126-9eea-ebae82bcf125_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Why Account Sprawl Happens</h2><p>Multi-account architectures rarely start sprawling. They become sprawling because account creation is rewarded and account boundaries are not.</p><p>The team that needs isolation creates an account. Provisioning is fast; the security team approves it, and the workload comes in. The team is unblocked. Nobody asks who owns the account in 18 months, when the workload changes shape, who decides which other accounts can call into it, who reviews the IAM policies written into it, or who confirms that logging is exported to the central account.</p><p>The account becomes orphaned at the moment it is provisioned. The team that owns the workload owns the workload. The platform team owns the foundation. Nobody owns the account.</p><p>Multiply this by 18 months of provisioning decisions. The org chart shifts twice. The platform team turns over a third of its engineers. The compliance scope expands to a new framework. The original team that requested the account no longer remembers why they needed it.</p><p>The boundary that was clear at creation time is now ambiguous. The account is still running. The workload inside it is operationally healthy. The boundary between this account and the others is undefined, and the security team has no record of who would answer questions about it.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Cloud Playbook is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>What Boundary Ownership Actually Means</h2><p>Boundary ownership is not the same as account ownership.</p><p>The team that operates a workload owns the workload. They are responsible for the application, deployment, on-call rotation, and cost. This is straightforward, and most organizations get it right.</p><p>Boundary ownership is the layer above. It governs the rules about what crosses the account, in either direction. Specifically:</p><ul><li><p><strong>Identity boundary.</strong> Who can assume IAM roles in this account from outside, and what those roles can do? Who can assume IAM roles into other accounts from this one, and what those roles can do. Trust relationships, condition keys, session policies.</p></li><li><p><strong>Network boundary.</strong> What VPC peering, Transit Gateway attachments, or PrivateLink endpoints exist into and out of this account? What CIDR ranges are routable? What ports are open at the security group level for cross-account traffic?</p></li><li><p><strong>Data boundary.</strong> What S3 buckets, KMS keys, or other resources in this account can be accessed from other accounts? What buckets, keys, or resources in other accounts can this account access? Resource policies, bucket policies, KMS key policies.</p></li><li><p><strong>Audit boundary.</strong> What CloudTrail, Config, GuardDuty, and Security Hub data flows out of this account into the central audit account? Whether the flow is enforced, whether it is verified, and who reviews it.</p></li><li><p><strong>Cost boundary.</strong> Which cost center is the spend in this account allocated to? Whether the allocation is automatic via tagging policy or manual via accounting reconciliation. Who reviews variance?</p></li></ul><p>Each of these boundaries has a different ownership profile. The team that runs the workload does not own the identity boundary. The platform team does. The compliance team does not own the network boundary. The networking team does. When ownership is explicitly named for each boundary, the team has a forwarding address for boundary-related questions. When ownership is implicit, the questions sit in nobody&#8217;s queue.</p><div><hr></div><h2>The Three Failure Patterns of Boundary Drift</h2><p>Boundary ownership ambiguity produces three predictable failure patterns.</p><ol><li><p><strong>The shadow trust relationship.</strong> A workload in account A needs to read a bucket in account B. The team writes a bucket policy. The team writes a role with the right permissions. The role works. Nobody flags that the bucket policy now grants cross-account access. Six months later, a security review discovers the policy and cannot trace why it was written or whether it is still needed. Removing it might break the workload. Leaving it leaves an undocumented trust path. The team chooses to leave it. The trust path stays.</p></li><li><p><strong>The audit gap.</strong> A new account is provisioned. The team configures the workload. The team forgets to enable CloudTrail forwarding to the central audit account. Eleven months later, the audit team is collecting evidence for SOC 2 Type II and discovers that the account's CloudTrail data has been missing for 11 months. The audit finding is significant. The remediation is a one-line configuration change that should have been made on day zero. Nobody owned the audit boundary, so nobody verified it.</p></li><li><p><strong>The networking debt.</strong> Each new account is given a Transit Gateway attachment. The attachments accumulate. The CIDR ranges overlap or nearly overlap. The platform team does not realize this until a new account cannot peer because the CIDR space is exhausted. The fix is a re-IP project that takes a quarter. The cause was a boundary nobody was reviewing as accounts were created.</p></li></ol><p>These patterns are not specific to one organization. They are predictable outcomes of the same root cause: boundaries without explicit owners drift, and drift compounds.</p><div><hr></div><h2>Four Questions That Surface Whether Your Boundaries Have Owners</h2><p>Before the next account is provisioned, the platform team should be able to answer four questions in writing. If they cannot, boundary ownership is the work that needs to come before more accounts.</p><ol><li><p><strong>For each existing account, who owns the identity boundary?</strong> The named individual or team that approves cross-account role assumptions, reviews trust policies, and decides when a role can be assumed from a new principal. If the answer is &#8220;the platform team&#8221; without a specific person and a documented review cadence, the answer is no.</p></li><li><p><strong>For each existing account, who owns the network boundary?</strong> The named individual or team that approves VPC peering, Transit Gateway attachments, and PrivateLink endpoints. The team that maintains the CIDR allocation registry. If the team cannot produce the registry, the boundary is unowned.</p></li><li><p><strong>For each existing account, who verifies that audit data is flowing to the central account?</strong> Not configured. Verified. The difference is monthly: configuration drifts, forwarding breaks, and retention policies change. The team that owns audit boundary verification runs a monthly check. If no team runs the check, the audit boundary is unowned.</p></li><li><p><strong>When a new account is provisioned, what is the first action that establishes ownership of each boundary?</strong> A defined process that names the identity boundary owner, the network boundary owner, the audit boundary verification owner, and the cost boundary owner before the account is handed to the workload team. If account provisioning does not include this step, every new account starts unowned.</p></li></ol><p>These four questions are diagnostic. The honest answer reveals which boundaries are owned, which are partially owned, and which are not owned at all. Most organizations discover that one or two of the four are well known, while the others are not.</p><div><hr></div><h2>What Changes When Boundaries Have Owners</h2><p>When boundary ownership is explicitly named, the failure patterns above stop occurring.</p><p>The shadow trust relationship is caught at creation. The identity boundary owner reviews the trust policy as part of the workload onboarding. Cross-account access has a documented justification, a documented review cadence, and a removal trigger if the workload changes.</p><p>The audit gap is caught within 30 days. The audit boundary owner runs a monthly verification. Configuration drift is detected before it becomes an audit finding. The CloudTrail forwarding question is answered before the auditor asks.</p><p>The networking debt is caught at the design phase. The network boundary owner maintains the CIDR registry and reviews each new attachment against the existing topology. Re-IP projects do not become quarter-long initiatives because the topology was managed instead of accumulated.</p><p>The platform team&#8217;s relationship to multi-account architecture changes. The team is no longer reactive to drift. The team is proactive about the boundary that prevents drift. The accounts continue to multiply as the workload portfolio grows. The boundaries stay coherent because they are owned.</p><div><hr></div><h2>Why This Is the Right Conversation Now</h2><p>The teams most exposed to boundary drift are SaaS organizations expanding into regulated customer segments.</p><p>A SOC 2 Type II audit produces findings on boundary drift. A FedRAMP authorization fails on it. A HIPAA business associate agreement requires the organization to demonstrate control over the boundary, not just over the workload. A customer requesting tenant isolation in a separate account requires the organization to have a defensible model for what crosses the account boundary and what does not.</p><p>The cost of unowned boundaries is invisible until one of these events. By that point, the cost is high.</p><p>Teams that name boundary ownership before the next account is provisioned do not incur these costs in the same way. The boundary is owned. The boundary is reviewed. The boundary survives org-chart changes because it is documented. The audit, the customer, and the framework all encounter a defended boundary, not a boundary that has been drifting for two years.</p><div><hr></div><p>On Wednesday, <strong>paid subscribers get the AWS Multi-Account Design Checklist for regulated SaaS platforms</strong>. The checklist covers account strategy, logging, identity, networking, tenant isolation, shared services, and audit evidence. Each section names the explicit owner, the verification cadence, and the artifact that confirms the boundary is intact. Use it to baseline your existing accounts before the next audit, or as the design document before the next account is provisioned.</p><p><strong>Upgrade If You Need Implementation, Not Just Ideas</strong></p><p>If you&#8217;re using these emails to guide real decisions on your platform, you&#8217;ll get more leverage from the paid version of The Cloud Playbook.</p><p>The free newsletter gives you patterns and language.</p><p>The paid newsletter turns those patterns into implementation kits you can ship inside a quarter:</p><ul><li><p>Concrete rollout plans (90&#8209;day roadmaps for each pattern)</p></li><li><p>Templates and checklists (policies, runbooks, tagging schemes, review checklists)</p></li><li><p>Real examples from high&#8209;stakes AWS environments (what we actually shipped and why)</p></li></ul><p>If the paid side doesn&#8217;t save you more than the subscription <span>cost in&nbsp;</span><strong><span>a single</span></strong> incident, audit cycle, or bad migration you avoid, you should cancel and keep the playbooks.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe&quot;,&quot;text&quot;:&quot;Upgrade to the Paid Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.thecloudplaybook.com/subscribe"><span>Upgrade to the Paid Cloud Playbook</span></a></p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a topic to read, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item><item><title><![CDATA[TCP #129: The scoring framework that picks ECS, EKS, or Lambda.]]></title><description><![CDATA[A weighted decision matrix across team maturity, operations, compliance, cost, and ownership with worked examples.]]></description><link>https://www.thecloudplaybook.com/p/ecs-eks-lambda-decision-framework</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/ecs-eks-lambda-decision-framework</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Thu, 02 Jul 2026 15:01:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Zdys!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most AWS compute decisions are made in a conference room. Two engineers argue for their preferred option. A staff engineer summarizes. The team picks. The decision is filed.</p><p>The conversation produces an outcome. It does not produce a defensible record. Six months later, when a similar workload arrives, the next team has the same conversation. There is no organizational memory. There is no consistency across teams. The compute estate fragments.</p><p>A scoring framework solves this. The framework does not eliminate judgment. It structures judgment so that the same workload produces the same recommendation regardless of which engineer scores it. It also produces a written record that future teams can reference and that leadership can audit when the cost trajectory deviates from the forecast.</p><p>The framework below is the one I would use with a real engineering team. It is calibrated for SaaS workloads, weighted for the dimensions that matter at 18-month horizons, and written at a level of detail that can be applied without further interpretation.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Zdys!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Zdys!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!Zdys!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!Zdys!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!Zdys!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Zdys!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1559000,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/203907995?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Zdys!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!Zdys!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!Zdys!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!Zdys!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a874e54-0a7f-4b07-b9bb-da4f9fe1e68e_1448x1086.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Why Most Frameworks Fail</h2><p>Frameworks fail in three predictable ways.</p><ol><li><p><strong>Too many dimensions.</strong> The team scores 12 attributes. The scoring takes three hours. The team abandons the framework after the second use because it feels like overhead.</p></li><li><p><strong>Wrong dimensions.</strong> The framework scores attributes that do not predict success. Language support, AWS region availability, and console UX. These attributes feel important, but rarely change the recommendation.</p></li><li><p><strong>No threshold rules.</strong> The framework produces a score for each option, but no rule for what the score means. Three options score within 10 percent of each other. The team argues again. The framework produced no decision support.</p></li></ol><p>The framework below is calibrated against these failure modes. Five dimensions, weighted by 18-month impact, with explicit threshold rules that produce a recommendation rather than a debate.</p>
      <p>
          <a href="https://www.thecloudplaybook.com/p/ecs-eks-lambda-decision-framework">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TCP #128: ECS, EKS, and Lambda are not the same decision]]></title><description><![CDATA[How team maturity, operational burden, and tenancy reshape the AWS compute choice, and what teams get wrong by treating them as alternatives]]></description><link>https://www.thecloudplaybook.com/p/ecs-eks-lambda-not-interchangeable</link><guid isPermaLink="false">https://www.thecloudplaybook.com/p/ecs-eks-lambda-not-interchangeable</guid><dc:creator><![CDATA[Amrut Patil]]></dc:creator><pubDate>Sun, 28 Jun 2026 14:21:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!CV9T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most engineering teams treat the choice of AWS compute as a matter of preference. </p><p>Lambda for the team that wants serverless. </p><p>ECS for the team that prefers containers. </p><p>EKS for the team that wants Kubernetes. </p><p>The conversation runs for an hour, the team picks the option that fits how it already works, and the service ships.</p><p>Eighteen months later, the choice is the most consequential architectural commitment the team has made. It governs cost, on-call load, hiring, audit posture, deployment cadence, and the team&#8217;s ability to take on the next workload type. It is harder to change than the database choice and almost as hard as changing the account topology.</p><p>The teams that get this right do not pick based on preference. </p><p>They pick based on five dimensions that determine whether the choice will compound value or compound debt: <strong>team maturity, operational burden, latency profile, tenancy model, and compliance exposure.</strong></p><p>The teams that get this wrong pick based on what they already know.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CV9T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CV9T!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!CV9T!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!CV9T!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!CV9T!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!CV9T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2027535,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.thecloudplaybook.com/i/202943599?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CV9T!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!CV9T!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!CV9T!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!CV9T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9744ee-78a5-41c3-ac12-5d3b1da2e3da_1448x1086.png 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Why Familiarity Is the Wrong Decision Criterion</h2><p>Familiarity is the default tiebreaker, and it is the wrong one.</p><p>The argument for familiarity is operational. The team that picks the technology it knows ships faster, debugs faster, and produces fewer incidents in the first six months. This is correct. It is also short-sighted.</p><p>The argument against familiarity is structural. Most engineering teams will make compute choices for workloads that grow in volume, expand in tenancy, and acquire new compliance scope. Familiarity at year zero produces operational comfort. By year two, the workload no longer matches the compute model the team chose, and the cost of the mismatch is paid by every team that runs on the same platform.</p><p>The teams that pick on familiarity end up with three compute platforms five years later, each one chosen by a different team for a different workload, each one operationally expensive. The platform team inherits the burden of supporting all three.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Cloud Playbook is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>The Five Dimensions That Should Drive the Choice</h2><p>Compute selection is a multi-dimensional decision. The five dimensions below yield recommendations that differ from those of the familiarity heuristic.</p><ol><li><p><strong>Team maturity</strong></p><p>Lambda is the lowest operational burden of the three. ECS is moderate. EKS is high. The team&#8217;s operational maturity does not need to match the platform&#8217;s complexity at year zero, but it needs to match within 18 months. A team with no Kubernetes experience that picks EKS will be operating an architecture they cannot debug for two quarters. A team with deep container experience that picks Lambda will hit cold-start, package size, and orchestration limits within a year.</p></li><li><p><strong>Operational burden</strong></p><p>Lambda offloads scaling, patching, and runtime management to AWS. ECS Fargate offloads node management, but the team still owns container lifecycle. EKS carries almost all of the operational burden with the team. The right question is not &#8220;which is easier.&#8221; The right question is &#8220;what fraction of the team&#8217;s capacity can be dedicated to running this platform six months from now?&#8221; If the answer is 0 percent, then the choice is between Lambda and Fargate. If the answer is 30 percent, EKS is on the table.</p></li><li><p><strong>Latency profile</strong></p><p>Lambda has cold-start variance, which can be addressed but never eliminated. The variance is incompatible with sub-100ms P99 SLOs for low-volume services. ECS and EKS have warm capacity by default. For latency-critical workloads, the cold-start question is not theoretical. It is the deciding factor.</p></li><li><p><strong>Tenancy model</strong></p><p>Lambda is shared-tenant by default, and tenant isolation is operationally awkward. ECS and EKS support tenant isolation through cluster topology, namespace boundaries, and IAM scope. For SaaS workloads that will need per-tenant isolation in the future, the tenancy commitment made today shapes whether that future is achievable.</p></li><li><p><strong>Compliance exposure</strong></p><p>All three services support common compliance frameworks. The differences are in the operational effort required to produce evidence. Lambda&#8217;s logging and configuration boundary is the simplest. EKS produces the most evidence but also requires the most work to properly configure it. The compliance frameworks the team will face in the next 24 months should drive this dimension.</p></li></ol><div><hr></div><h2>Why Lambda Is Misused</h2><p>Lambda is the most misused compute service in AWS. The misuse is not technical. It is economic.</p><p>Lambda is priced per invocation and per millisecond of execution. At low volume, this is dramatically cheaper than running a container fleet. At high volume, it is dramatically more expensive. The cost crossover varies by workload, but for typical request-response services, it sits somewhere between 100 and 500 RPS sustained. Below the crossover, Lambda saves money. Above the crossover, Lambda costs 2 to 5 times as much as an equivalent ECS or EKS deployment.</p><p>Most teams choose Lambda based on their current volume. They forecast linearly. They do not model the workload at the volume it will reach in 18 months. By the time the cost trajectory becomes visible in the AWS bill, the architecture is load-bearing, and the migration cost is high.</p><p>The Lambda choice is not wrong. The Lambda choice without a written cost trajectory at 10x current volume is wrong.</p><div><hr></div><h2>Why EKS Is Often the Wrong Default</h2><p>EKS has become the default container choice for engineering teams that want maximum flexibility. The argument is reasonable: Kubernetes is the broadest ecosystem, the most portable, the most powerful.</p><p>The argument also misses two structural realities.</p><p>First, the operational burden is not optional. EKS requires the team to operate cluster networking, ingress, pod scheduling, node lifecycle, secrets management, observability instrumentation, and security boundaries. AWS manages the control plane. The team manages everything else. The team that picks EKS is committing to roughly 0.5 to 1.0 FTE of platform work that does not directly produce product value.</p><p>Second, the flexibility is rarely used. Most workloads that pick EKS do not use the features that justify the operational burden. They run a deployment, a service, and an ingress. ECS Fargate would run the same workload with a fraction of the operational overhead and no portability cost; the team would actually exercise.</p><p>EKS is the right choice when the team has a portfolio of workloads that justify the platform investment, a strong commitment to Kubernetes patterns across services, or a specific feature, such as custom schedulers, that ECS does not support. It is the wrong choice for the team to pick it because the rest of the industry is using it.</p><div><hr></div><h2>Why ECS Is Underestimated</h2><p>ECS does not have the brand prestige of Kubernetes. It lacks the elegance of Lambda. It has the property that matters more than either: it requires the least operational burden for the broadest range of workloads.</p><p>ECS Fargate runs containers without node management. It integrates with the rest of AWS through native primitives rather than abstractions. It produces logs, metrics, and traces through standard AWS instrumentation. It has been generally available longer than EKS and is operationally mature.</p><p>For most SaaS workloads, ECS Fargate is the correct default. It supports latency profiles, tenancy models, and compliance frameworks. It does not require the team to operate a Kubernetes cluster. It does not lock the team into Lambda&#8217;s pricing trajectory.</p><p>The teams that build on ECS as the default and reach for Lambda or EKS only when the workload demands it produce platforms with lower operational burden and better cost trajectories than the teams that pick on preference.</p><div><hr></div><h2>Four Questions That Drive the Right Choice</h2><p>Before the team picks a compute service, four questions should be answered in writing. The questions take an hour. They prevent the wrong choice from compounding for years.</p><ol><li><p><strong>What is the team&#8217;s operational capacity for this workload at month 12</strong></p><p>Not month zero. The team has Slack at month zero because the workload is new. By month 12, the workload is one of several. If the team will not have 30 percent of an FTE available to run a Kubernetes cluster, EKS is not on the table.</p></li><li><p><strong>At 10x current volume, what does this cost?</strong></p><p>Lambda&#8217;s cost trajectory hides at low volume and surfaces at high volume. Modeling 10x growth at decision time exposes the cost cliff. If the model shows Lambda becoming uneconomic at the forecast volume, the choice should be ECS or EKS.</p></li><li><p><strong>What latency SLO does the workload need?</strong></p><p>Sub-100ms P99 with low volume is incompatible with Lambda cold-start variance unless provisioned concurrency is paid for. For workloads with strict latency requirements and low base load, ECS or EKS are the only viable choices.</p></li><li><p><strong>What tenancy and compliance requirements will the workload need in 24 months?</strong> </p><p>If the future includes per-tenant isolation for regulated customers, the compute choice today should not foreclose that future. Lambda&#8217;s tenancy model is the most awkward to evolve. ECS and EKS both support evolution but require different paths.</p></li></ol><p>The team that answers these four questions makes a different choice than the team that picks based on preference. The choice is not always the same. It is always more defensible.</p><div><hr></div><h2>What Changes When Computing Is a Risk Decision</h2><p>Engineering organizations that treat compute selection as a risk decision rather than a preference produce different outcomes.</p><p>The platform team consolidates on fewer compute models, reducing operational burden and improving the team&#8217;s ability to ship golden paths.</p><p>The cost forecast is accurate because each workload was modeled during growth, before the architecture shipped.</p><p>The compliance posture is consistent because the compute choice was filtered through the compliance scope at decision time.</p><p>The team&#8217;s hiring profile becomes coherent because computed commitments determine which kinds of engineers the team needs to recruit, develop, and retain.</p><p>The choice of a computer does not become invisible. It becomes the single most important architectural commitment the team makes. The teams that treat it that way ship platforms that compound. The teams that treat it as a preference ship platforms that fragment.</p><div><hr></div><p>On Wednesday, paid subscribers get the complete <strong>ECS vs EKS vs Lambda decision framework</strong>: a scoring matrix that evaluates a candidate workload across team maturity, operational complexity, compliance impact, cost trajectory, and ownership. </p><p>The framework includes weighted scoring, the threshold rules that drive the recommendation, and three worked examples covering an internal service, a customer-facing API, and a regulated multi-tenant workload.</p><div><hr></div><p><strong>Upgrade If You Need Implementation, Not Just Ideas</strong></p><p>If you&#8217;re using these emails to guide real decisions on your platform, you&#8217;ll get more leverage from the paid version of The Cloud Playbook.</p><p>The free newsletter gives you patterns and language.</p><p>The paid newsletter turns those patterns into implementation kits you can ship inside a quarter:</p><ul><li><p>Concrete rollout plans (90&#8209;day roadmaps for each pattern)</p></li><li><p>Templates and checklists (policies, runbooks, tagging schemes, review checklists)</p></li><li><p>Real examples from high&#8209;stakes AWS environments (what we actually shipped and why)</p></li></ul><p>If the paid side doesn&#8217;t save you more than the subscription in <strong>one</strong> incident, audit cycle, or bad migration you avoid, you should cancel and keep the playbooks.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/subscribe&quot;,&quot;text&quot;:&quot;Upgrade to the Paid Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.thecloudplaybook.com/subscribe"><span>Upgrade to the Paid Cloud Playbook</span></a></p><div><hr></div><h2><strong>That&#8217;s it for today!</strong></h2><p>Did you enjoy this newsletter issue?</p><p>Share with your friends, colleagues, and your favorite social media platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Cloud Playbook&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.thecloudplaybook.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Cloud Playbook</span></a></p><p><strong>Until next week &#8212; Amrut</strong></p><div><hr></div><h2><strong>Get in touch</strong></h2><p>You can find me on <a href="https://www.linkedin.com/in/patilamrut/">LinkedIn</a> or <a href="https://twitter.com/realamrutpatil">X</a>.</p><p>If you would like to request a reading topic, please feel free to contact me directly via LinkedIn or X.</p>]]></content:encoded></item></channel></rss>