<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: MeteorOps</title>
    <description>The latest articles on DEV Community by MeteorOps (meteorops).</description>
    <link>https://dev.to/meteorops</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F7873%2Fad0d7cdb-d642-474a-9592-c8d08685ca13.png</url>
      <title>DEV Community: MeteorOps</title>
      <link>https://dev.to/meteorops</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/meteorops"/>
    <language>en</language>
    <item>
      <title>Datadog Pricing: What You Pay and How to Cut the Bill</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Sat, 14 Nov 2026 21:30:02 +0000</pubDate>
      <link>https://dev.to/meteorops/datadog-pricing-what-you-pay-and-how-to-cut-the-bill-1a5f</link>
      <guid>https://dev.to/meteorops/datadog-pricing-what-you-pay-and-how-to-cut-the-bill-1a5f</guid>
      <description>&lt;p&gt;On a Datadog bill for 50 hosts, the $15 per host is 17% of the total:&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Datadog pricing is a price list of separate products, and each product has its own unit.&lt;/p&gt;

&lt;p&gt;Infrastructure Monitoring costs $15 per host per month on the Pro plan (billed annually), or $18 on-demand.&lt;/p&gt;

&lt;p&gt;APM adds $31 per host.&lt;/p&gt;

&lt;p&gt;Logs cost $0.10 per GB to ingest plus $1.70 per million events to index for 15 days.&lt;/p&gt;

&lt;p&gt;Custom metrics cost $5 per 100 above what your hosts include.&lt;/p&gt;

&lt;p&gt;So the host price tells you very little. The bill follows 4 things your team controls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How many hosts and containers run at the busiest hours of the month&lt;/li&gt;
&lt;li&gt;How many tag combinations your custom metrics have&lt;/li&gt;
&lt;li&gt;How many log events you index, and for how many days&lt;/li&gt;
&lt;li&gt;How much of it you committed to in advance&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the worked example below, 50 hosts cost $4,360 a month at list price, and the $15 host line is 17% of it.&lt;/p&gt;

&lt;p&gt;3 changes bring that bill to $2,953.&lt;/p&gt;

&lt;p&gt;All prices here are Datadog's public list prices for the US site, in USD, checked on November 14, 2026 against the &lt;a href="https://www.datadoghq.com/pricing/list/" rel="noopener noreferrer"&gt;Datadog price list&lt;/a&gt; and the &lt;a href="https://docs.datadoghq.com/account_management/billing/pricing/" rel="noopener noreferrer"&gt;billing docs&lt;/a&gt;. Your contract can differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  Datadog pricing is a price list, one unit per product
&lt;/h2&gt;

&lt;p&gt;The Datadog price list has a row for every product, and you pay for each one you turn on.&lt;/p&gt;

&lt;p&gt;These are the lines a typical startup setup uses:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Billed annually&lt;/th&gt;
&lt;th&gt;Month-to-month&lt;/th&gt;
&lt;th&gt;On-demand&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure Pro&lt;/td&gt;
&lt;td&gt;Host, per month&lt;/td&gt;
&lt;td&gt;$15&lt;/td&gt;
&lt;td&gt;$18&lt;/td&gt;
&lt;td&gt;$18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure Enterprise&lt;/td&gt;
&lt;td&gt;Host, per month&lt;/td&gt;
&lt;td&gt;$23&lt;/td&gt;
&lt;td&gt;$27&lt;/td&gt;
&lt;td&gt;$27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APM&lt;/td&gt;
&lt;td&gt;APM host, per month&lt;/td&gt;
&lt;td&gt;$31&lt;/td&gt;
&lt;td&gt;$36&lt;/td&gt;
&lt;td&gt;$36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APM Pro&lt;/td&gt;
&lt;td&gt;APM host, per month&lt;/td&gt;
&lt;td&gt;$35&lt;/td&gt;
&lt;td&gt;$42&lt;/td&gt;
&lt;td&gt;$42&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APM Enterprise&lt;/td&gt;
&lt;td&gt;APM host, per month&lt;/td&gt;
&lt;td&gt;$40&lt;/td&gt;
&lt;td&gt;$48&lt;/td&gt;
&lt;td&gt;$48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database Monitoring&lt;/td&gt;
&lt;td&gt;Database host, per month&lt;/td&gt;
&lt;td&gt;$70&lt;/td&gt;
&lt;td&gt;$84&lt;/td&gt;
&lt;td&gt;$84&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Containers above the included ones&lt;/td&gt;
&lt;td&gt;Container&lt;/td&gt;
&lt;td&gt;$1 per month&lt;/td&gt;
&lt;td&gt;$1 per month&lt;/td&gt;
&lt;td&gt;$0.002 per hour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom metrics above the included ones&lt;/td&gt;
&lt;td&gt;100 metrics, per month&lt;/td&gt;
&lt;td&gt;$5&lt;/td&gt;
&lt;td&gt;$5&lt;/td&gt;
&lt;td&gt;$5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Log ingestion&lt;/td&gt;
&lt;td&gt;GB&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indexed logs, 15-day retention&lt;/td&gt;
&lt;td&gt;1 million events&lt;/td&gt;
&lt;td&gt;$1.70&lt;/td&gt;
&lt;td&gt;$2.04&lt;/td&gt;
&lt;td&gt;$2.55&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indexed spans, 15-day retention&lt;/td&gt;
&lt;td&gt;1 million spans&lt;/td&gt;
&lt;td&gt;$1.70&lt;/td&gt;
&lt;td&gt;$2.04&lt;/td&gt;
&lt;td&gt;$2.55&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Synthetic API tests&lt;/td&gt;
&lt;td&gt;10,000 test runs&lt;/td&gt;
&lt;td&gt;$5&lt;/td&gt;
&lt;td&gt;$6&lt;/td&gt;
&lt;td&gt;$7.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Synthetic browser tests&lt;/td&gt;
&lt;td&gt;1,000 test runs&lt;/td&gt;
&lt;td&gt;$12&lt;/td&gt;
&lt;td&gt;$15&lt;/td&gt;
&lt;td&gt;$18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RUM Measure&lt;/td&gt;
&lt;td&gt;1,000 sessions&lt;/td&gt;
&lt;td&gt;$0.15&lt;/td&gt;
&lt;td&gt;$0.18&lt;/td&gt;
&lt;td&gt;$0.22&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things in this table decide most bills.&lt;/p&gt;

&lt;p&gt;First: a host with Infrastructure Pro and APM costs $46 a month, 3 times the number on the pricing page.&lt;/p&gt;

&lt;p&gt;Second: the last 8 rows are usage.&lt;/p&gt;

&lt;p&gt;Nobody signs off on them. They grow with every deploy.&lt;/p&gt;

&lt;p&gt;Host = a predictable floor. Usage = the part that surprises you.&lt;/p&gt;

&lt;h2&gt;
  
  
  A host is billed on the busiest hours of the month
&lt;/h2&gt;

&lt;p&gt;Datadog counts your hosts every hour.&lt;/p&gt;

&lt;p&gt;On the default plan (Datadog calls it the high watermark plan) you pay for the highest count of the month after the top 1% of hours is dropped.&lt;/p&gt;

&lt;p&gt;A 30 day month has 720 hourly readings. The top 1% is 7.2 of them, and Datadog rounds that up to 8.&lt;/p&gt;

&lt;p&gt;The APM billing page spells the rule out for APM hosts: Datadog charges on the ninth highest reading of the month (the eighth in February). Infrastructure hosts follow the same 99% rule.&lt;/p&gt;

&lt;p&gt;Here is what that does to an autoscaling cluster:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You run 40 nodes all month&lt;/li&gt;
&lt;li&gt;A load test keeps 100 nodes up during 8 hourly readings → you pay for 40 hosts&lt;/li&gt;
&lt;li&gt;It shows up in a ninth reading → you pay for 100 hosts, for the whole month&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rule: 9 high readings set the price of the other 711.&lt;/p&gt;

&lt;p&gt;The 8 readings are a budget for the whole month, and a test that starts mid-hour uses an extra one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8u5705a3ip4z0l5v22ix.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8u5705a3ip4z0l5v22ix.webp" alt="Two charts of host count over a month: a spike to 100 nodes for 8 hours is billed as 40 hosts, a spike for 9 hours is billed as 100 hosts" width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Datadog drops the top 1% of the 720 hourly readings. A ninth high reading sets the host count for the month.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What counts as a host: a server, a VM, a Kubernetes node, an Azure App Service Plan instance or a Heroku dyno. A VM seen by both the Agent and the cloud integration counts once.&lt;/p&gt;

&lt;p&gt;If your fleet scales up and down every day, ask for the hybrid monthly/hourly plan. You commit to a monthly minimum and pay an hourly rate for host hours above it.&lt;/p&gt;

&lt;p&gt;The same hourly counting applies to APM hosts and database hosts. (Yes, one long load test can raise the host line, the APM line and the container line.)&lt;/p&gt;

&lt;p&gt;If you autoscale on Kubernetes, the settings that decide how long extra nodes stay up are in my guide on &lt;a href="https://meteorops.com/blog/how-to-set-up-kubernetes-autoscaling-without-creating-cost-surprises" rel="noopener noreferrer"&gt;Kubernetes autoscaling without cost surprises&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Containers and custom metrics come with the host, up to a limit
&lt;/h2&gt;

&lt;p&gt;Each Infrastructure host includes an allotment of other products:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Included with each host&lt;/th&gt;
&lt;th&gt;Pro&lt;/th&gt;
&lt;th&gt;Enterprise&lt;/th&gt;
&lt;th&gt;Above the allotment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Containers&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;$1 per container per month prepaid, $0.002 per hour on-demand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom metrics&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;$5 per 100 per month at list price&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The allotments are pooled across the account. 50 Pro hosts include 250 containers and 5,000 custom metrics, wherever they run.&lt;/p&gt;

&lt;p&gt;A Kubernetes node that runs 20 containers uses 4 hosts' worth of the container allotment.&lt;/p&gt;

&lt;p&gt;The on-demand container rate looks small: $0.002 an hour is $1.46 over a 730 hour month, 46% more than the prepaid $1.&lt;/p&gt;

&lt;p&gt;Kubernetes pause containers are excluded from the count.&lt;/p&gt;

&lt;p&gt;One mistake to avoid: installing the Agent inside every container. Datadog then bills each container as a host.&lt;/p&gt;

&lt;p&gt;Run 1 containerized Agent per node.&lt;/p&gt;
&lt;h2&gt;
  
  
  Custom metrics multiply with every tag
&lt;/h2&gt;

&lt;p&gt;This is the line that is hardest to predict.&lt;/p&gt;

&lt;p&gt;A custom metric is any metric that does not come from a Datadog integration: everything you send through DogStatsD, a custom check or a log-based metric.&lt;/p&gt;

&lt;p&gt;Datadog counts tag combinations, and 1 metric name can hold thousands of them:&lt;/p&gt;

&lt;p&gt;1 custom metric = 1 metric name + 1 unique combination of tag values (the host tag included).&lt;/p&gt;

&lt;p&gt;Take a metric named &lt;code&gt;checkout.latency&lt;/code&gt; with 3 tags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;endpoint&lt;/code&gt;: 20 values&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;status&lt;/code&gt;: 3 values&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pod&lt;/code&gt;: 50 values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If every combination reports, that is 20 x 3 x 50 = 3,000 custom metrics.&lt;/p&gt;

&lt;p&gt;The metric type multiplies it again:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric type&lt;/th&gt;
&lt;th&gt;Custom metrics per tag combination&lt;/th&gt;
&lt;th&gt;checkout.latency&lt;/th&gt;
&lt;th&gt;Cost above the allotment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Count, rate or gauge&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;td&gt;$150 a month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Histogram (default aggregations)&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;15,000&lt;/td&gt;
&lt;td&gt;$750 a month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distribution&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;15,000&lt;/td&gt;
&lt;td&gt;$750 a month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distribution with percentiles&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;30,000&lt;/td&gt;
&lt;td&gt;$1,500 a month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One metric name, one line of code, $1,500 a month.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9igddh232j6ysfevntqx.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9igddh232j6ysfevntqx.webp" alt="Multiplication diagram: endpoint 20 values times status 3 values times pod 50 values equals 3,000 custom metrics, times 10 as a distribution with percentiles equals 30,000 custom metrics or $1,500 a month" width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;1 metric name with 3 tags becomes 3,000 custom metrics, and 30,000 as a distribution with percentiles.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now add a &lt;code&gt;customer_id&lt;/code&gt; tag with 200 values and multiply the table by up to 200.&lt;/p&gt;

&lt;p&gt;Two details work in your favor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only combinations that actually report are counted, and the count follows your most detailed tag&lt;/li&gt;
&lt;li&gt;Billing uses the monthly average of the hourly count, so a 1 hour burst of new tag values costs 1/720 of a full month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you get the tags back under control without changing code? Metrics without Limits.&lt;/p&gt;

&lt;p&gt;It lets you pick, per metric, which tags stay queryable. Datadog then bills two volumes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Indexed custom metrics:&lt;/strong&gt; the combinations of the tags you kept, at the $5 per 100 list price&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ingested custom metrics:&lt;/strong&gt; everything your code still sends for the metrics you configured, at $0.10 per 100 above the allotment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keeping only &lt;code&gt;endpoint&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt; on &lt;code&gt;checkout.latency&lt;/code&gt; takes it from 3,000 indexed combinations to 60.&lt;/p&gt;
&lt;h2&gt;
  
  
  Logs are billed twice: once to ingest, once to index
&lt;/h2&gt;

&lt;p&gt;Every log you send pays $0.10 per GB at ingestion.&lt;/p&gt;

&lt;p&gt;Every log you keep searchable pays again, per million events, by retention:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Index retention&lt;/th&gt;
&lt;th&gt;Billed annually&lt;/th&gt;
&lt;th&gt;Month-to-month&lt;/th&gt;
&lt;th&gt;On-demand&lt;/th&gt;
&lt;th&gt;300 million events a month (annual)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3 days&lt;/td&gt;
&lt;td&gt;$1.06&lt;/td&gt;
&lt;td&gt;$1.27&lt;/td&gt;
&lt;td&gt;$1.59&lt;/td&gt;
&lt;td&gt;$318&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7 days&lt;/td&gt;
&lt;td&gt;$1.27&lt;/td&gt;
&lt;td&gt;$1.52&lt;/td&gt;
&lt;td&gt;$1.91&lt;/td&gt;
&lt;td&gt;$381&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15 days&lt;/td&gt;
&lt;td&gt;$1.70&lt;/td&gt;
&lt;td&gt;$2.04&lt;/td&gt;
&lt;td&gt;$2.55&lt;/td&gt;
&lt;td&gt;$510&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30 days&lt;/td&gt;
&lt;td&gt;$2.50&lt;/td&gt;
&lt;td&gt;$3.00&lt;/td&gt;
&lt;td&gt;$3.75&lt;/td&gt;
&lt;td&gt;$750&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Ingestion is cheap. Indexing is the bill.&lt;/p&gt;

&lt;p&gt;500 GB of logs costs $50 to ingest. The same logs, as 300 million events indexed for 15 days, cost $510.&lt;/p&gt;

&lt;p&gt;That split is also the way out: you can ingest everything and index a part of it.&lt;/p&gt;

&lt;p&gt;An exclusion filter on an index drops matching logs before they are indexed. The excluded logs still show in Live Tail, can still feed log-based metrics and can still go to your archive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzznfcgh0cif917fbxzxz.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzznfcgh0cif917fbxzxz.webp" alt="Flow diagram: 500 GB of logs are ingested at $0.10 per GB for $50, pass an exclusion filter, and are indexed for 15 days at $1.70 per million events for $510; excluded logs go to Live Tail, metrics and archive" width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Every log pays for ingestion. Only the logs that pass the exclusion filters pay for indexing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The two filters I would add first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;status:DEBUG                                        exclude 100%
source:nginx AND http.status_code:[200 TO 299]      exclude 95%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first one can be switched off from the UI or the API during an incident, when you want the debug logs back.&lt;/p&gt;

&lt;p&gt;The second keeps every 3xx, 4xx and 5xx request and 5% of the successful ones, which is enough to see the trend.&lt;/p&gt;

&lt;p&gt;Two more log facts for your budget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Indexed logs above your commitment are billed on-demand, at a 50% premium ($2.55 against $1.70)&lt;/li&gt;
&lt;li&gt;Each index can have a daily quota. When a service starts logging at debug level in production, indexing stops at the quota. The logs still reach Live Tail and your archive, and you still pay the $0.10 per GB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For logs you must keep for months but rarely read, Flex Logs stores them at $0.05 per million events per month, with query capacity bought separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  APM adds a second host price, with spans included
&lt;/h2&gt;

&lt;p&gt;An APM host is any host that sends traces. It costs $31 a month on top of the Infrastructure price.&lt;/p&gt;

&lt;p&gt;Each APM host includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;150 GB of ingested spans a month&lt;/li&gt;
&lt;li&gt;1 million indexed spans a month, kept for 15 days&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Above that: $0.10 per ingested GB, and $1.70 per million indexed spans at 15-day retention.&lt;/p&gt;

&lt;p&gt;Both allotments are pooled across your APM hosts.&lt;/p&gt;

&lt;p&gt;50 APM hosts include 7,500 GB of ingested spans and 50 million indexed spans a month. The host count is the easier place to overpay: tracing left on for hosts that run batch jobs and internal tools nobody traces.&lt;/p&gt;

&lt;p&gt;Only hosts that send traces are APM hosts. A node pool for untraced workloads is $31 a month saved per node.&lt;/p&gt;

&lt;p&gt;If you do pass the allotment, set sampling per service in the tracing library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export DD_TRACE_SAMPLING_RULES='[
  {"service": "checkout", "resource": "GET /checkout", "sample_rate": 1},
  {"service": "checkout", "sample_rate": 0.2}
]'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps every trace that starts at &lt;code&gt;GET /checkout&lt;/code&gt; and 20% of the other traces that start in the service.&lt;/p&gt;

&lt;p&gt;Resource rules need a recent Java, Python, Go or PHP tracer. Other languages take the per-service rule only.&lt;/p&gt;

&lt;p&gt;Retention filters then decide which ingested spans are indexed.&lt;/p&gt;

&lt;p&gt;The Intelligent Retention Filter keeps a sample of errors and slow traces at no charge, so start by trimming your custom filters and the rate of the Error Default one.&lt;/p&gt;

&lt;h2&gt;
  
  
  A worked Datadog bill for 50 hosts
&lt;/h2&gt;

&lt;p&gt;The setup, with my assumptions stated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;50 Kubernetes nodes, Infrastructure Pro, billed annually&lt;/li&gt;
&lt;li&gt;APM on all 50 nodes, spans inside the allotment&lt;/li&gt;
&lt;li&gt;1,000 containers on average (20 per node)&lt;/li&gt;
&lt;li&gt;20,000 custom metrics&lt;/li&gt;
&lt;li&gt;500 GB of logs a month, 300 million events, all indexed for 15 days&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Line&lt;/th&gt;
&lt;th&gt;Calculation&lt;/th&gt;
&lt;th&gt;Per month&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure Pro&lt;/td&gt;
&lt;td&gt;50 x $15&lt;/td&gt;
&lt;td&gt;$750&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APM&lt;/td&gt;
&lt;td&gt;50 x $31&lt;/td&gt;
&lt;td&gt;$1,550&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Containers&lt;/td&gt;
&lt;td&gt;(1,000 - 250 included) x $1&lt;/td&gt;
&lt;td&gt;$750&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom metrics&lt;/td&gt;
&lt;td&gt;(20,000 - 5,000 included) / 100 x $5&lt;/td&gt;
&lt;td&gt;$750&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Log ingestion&lt;/td&gt;
&lt;td&gt;500 GB x $0.10&lt;/td&gt;
&lt;td&gt;$50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indexed logs&lt;/td&gt;
&lt;td&gt;300 x $1.70&lt;/td&gt;
&lt;td&gt;$510&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$4,360&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;$4,360 a month is $52,320 a year.&lt;/p&gt;

&lt;p&gt;The line everyone quotes ($15 per host) is $750 of it: 17%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff5b3fnbpq1u8vas1nark.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff5b3fnbpq1u8vas1nark.webp" alt="Bar chart of a Datadog bill for 50 hosts, $4,360 a month: APM $1,550, Infrastructure Pro $750, containers $750, custom metrics $750, indexed logs $510, log ingestion $50" width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The 50 host bill at list price. The $15 per host line is 17% of it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The same usage with no commitment, at on-demand rates, comes to $5,360 a month. That is 23% more for the same usage.&lt;/p&gt;

&lt;p&gt;Now the same company after 3 changes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tracing only on the 35 nodes that run traced services&lt;/td&gt;
&lt;td&gt;$1,550&lt;/td&gt;
&lt;td&gt;$1,085&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metrics without Limits: 20,000 indexed custom metrics down to 8,000&lt;/td&gt;
&lt;td&gt;$750&lt;/td&gt;
&lt;td&gt;$150 + up to $15 for ingested&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exclusion filters: 30% of log events indexed&lt;/td&gt;
&lt;td&gt;$510&lt;/td&gt;
&lt;td&gt;$153&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything else unchanged&lt;/td&gt;
&lt;td&gt;$1,550&lt;/td&gt;
&lt;td&gt;$1,550&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$4,360&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$2,953&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;$1,407 a month less: 32%.&lt;/p&gt;

&lt;p&gt;These are list prices. Datadog lists volume discounts from 500 hosts a month, and a sales conversation changes the numbers long before that.&lt;/p&gt;
&lt;h2&gt;
  
  
  Commit to your baseline, pay on-demand for the rest
&lt;/h2&gt;

&lt;p&gt;Datadog has 3 price columns: billed annually, month-to-month and on-demand.&lt;/p&gt;

&lt;p&gt;Commitment = a quantity per product that you pay for whether you use it or not.&lt;/p&gt;

&lt;p&gt;On-demand = everything above it, at the highest price.&lt;/p&gt;

&lt;p&gt;The billing docs give the formula:&lt;/p&gt;

&lt;p&gt;allotments + committed usage = included usage. Billable usage minus included usage = on-demand usage.&lt;/p&gt;

&lt;p&gt;The premium depends on the product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hosts: $18 against $15, 20% more&lt;/li&gt;
&lt;li&gt;Indexed logs and spans: $2.55 against $1.70, 50% more&lt;/li&gt;
&lt;li&gt;Containers: $1.46 against $1 over a full month, 46% more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So my rule is simple: commit to what you used in your quietest month, and let growth run on-demand until the next renewal.&lt;/p&gt;

&lt;p&gt;Commit too low and you pay up to 50% extra on the difference (16% on APM hosts, 20% on hosts, 50% on indexed logs).&lt;/p&gt;

&lt;p&gt;Commit too high and you pay 100% for something you never used.&lt;/p&gt;
&lt;h2&gt;
  
  
  Cut the bill in this order
&lt;/h2&gt;

&lt;p&gt;Start where the money is. In the example above that is APM hosts, custom metrics and indexed logs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the bill by product:&lt;/strong&gt; Plan and Usage shows month-to-date and projected cost per product, and the top custom metric names by share of cost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exclude logs you never search:&lt;/strong&gt; debug logs, health checks and successful requests first&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shorten retention:&lt;/strong&gt; 300 million events at 7 days cost $381 against $510 at 15 days. Send the rest to an archive in your own bucket&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set a daily quota on every index:&lt;/strong&gt; a bad deploy then indexes 1 day's quota at most. Logs past the quota are not searchable, so add the warning threshold&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drop tags with Metrics without Limits:&lt;/strong&gt; start with the 10 metric names at the top of the usage page. Datadog marks the tags queried in the last 30 days&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop percentiles you do not graph:&lt;/strong&gt; they double the count of a distribution metric&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turn tracing off where nobody reads traces:&lt;/strong&gt; every host that sends traces is an APM host&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep all spikes of the month inside 8 hourly readings, or move to the hourly plan:&lt;/strong&gt; the high-water mark decides the month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alert on your own usage:&lt;/strong&gt; Datadog publishes it as metrics&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The usage metrics for the last point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;datadog.estimated_usage.hosts
datadog.estimated_usage.containers
datadog.estimated_usage.metrics.custom
datadog.estimated_usage.logs.ingested_bytes
datadog.estimated_usage.logs.ingested_events
datadog.estimated_usage.apm_hosts
datadog.estimated_usage.apm.ingested_bytes
datadog.estimated_usage.apm.indexed_spans
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put an anomaly monitor on the log and custom metric ones. You then hear about a cost spike the same day it starts.&lt;/p&gt;

&lt;p&gt;Filter &lt;code&gt;logs.ingested_events&lt;/code&gt; by &lt;code&gt;datadog_is_excluded:false&lt;/code&gt; to watch what gets indexed.&lt;/p&gt;

&lt;p&gt;The same approach works on the cloud bill itself. I wrote it down in &lt;a href="https://meteorops.com/blog/how-to-cut-cloud-costs-without-slowing-teams" rel="noopener noreferrer"&gt;how to cut cloud costs without slowing teams&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pay for Datadog when it saves an engineer
&lt;/h2&gt;

&lt;p&gt;Yes, I help companies lower this bill. My first advice is to cut it before you leave it.&lt;/p&gt;

&lt;p&gt;The alternative to Datadog is usually Prometheus, Grafana, Loki and an OpenTelemetry Collector that somebody on your team runs.&lt;/p&gt;

&lt;p&gt;The license is free. The engineer is the cost.&lt;/p&gt;

&lt;p&gt;My position:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Up to about 20 engineers:&lt;/strong&gt; buy it. $4,000 a month is cheaper than the part of an engineer that a self-hosted stack takes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When the bill passes the cost of an engineer:&lt;/strong&gt; cut it with the list above before you think about leaving&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When it is still too high after that:&lt;/strong&gt; move the most expensive signal first (often logs) and keep the rest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exceptions: if you already run Prometheus well, or you are bound to keep data in your own account, start self-hosted.&lt;/p&gt;

&lt;p&gt;Instrument with OpenTelemetry either way. Datadog accepts it, and it keeps the exit open.&lt;/p&gt;

&lt;p&gt;Check how your OTLP metrics are billed first: metrics outside a Datadog integration count as custom metrics.&lt;/p&gt;

&lt;p&gt;I compare the two paths in &lt;a href="https://meteorops.com/blog/how-to-build-a-startup-observability-stack" rel="noopener noreferrer"&gt;how to build a startup observability stack&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Datadog cost checklist
&lt;/h2&gt;

&lt;p&gt;Always:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 Agent per node&lt;/li&gt;
&lt;li&gt;A commitment equal to your quietest month&lt;/li&gt;
&lt;li&gt;Exclusion filters on debug logs and successful requests&lt;/li&gt;
&lt;li&gt;A daily quota on every log index&lt;/li&gt;
&lt;li&gt;The shortest index retention your on-call needs, and an archive for the rest&lt;/li&gt;
&lt;li&gt;No user, customer or request ID as a metric tag&lt;/li&gt;
&lt;li&gt;Percentiles only on metrics that have a graph or a monitor&lt;/li&gt;
&lt;li&gt;Tracing only on hosts where somebody reads traces&lt;/li&gt;
&lt;li&gt;Monitors on the &lt;code&gt;datadog.estimated_usage&lt;/code&gt; metrics&lt;/li&gt;
&lt;li&gt;A look at the projected cost on the 10th of every month&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How does Datadog pricing work?
&lt;/h3&gt;

&lt;p&gt;Each Datadog product has its own unit and price. Infrastructure Monitoring and APM are priced per host per month, logs per GB ingested and per million events indexed, custom metrics per 100, and Synthetics and RUM per test run and per session. You commit to a quantity per product and pay a higher on-demand rate above it.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much does Datadog cost per host?
&lt;/h3&gt;

&lt;p&gt;Infrastructure Pro is $15 per host per month billed annually and $18 on-demand. Enterprise is $23 and $27. With APM at $31, a traced host costs $46 a month before containers, custom metrics and logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is Datadog so expensive?
&lt;/h3&gt;

&lt;p&gt;The host price is a small part of the bill. Custom metrics multiply with every tag, logs are charged at ingestion and again at indexing, and hosts are billed on the busiest hours of the month. In the 50 host example above, the host line is 17% of $4,360.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Datadog free?
&lt;/h3&gt;

&lt;p&gt;Partly. Datadog has a free trial, and when it ends you can move to the Free tier: up to 5 Basic hosts with 1-day metric retention, at no cost. Container monitoring is listed from the Pro plan, at $15 per host.&lt;/p&gt;

&lt;h3&gt;
  
  
  How are Datadog custom metrics billed?
&lt;/h3&gt;

&lt;p&gt;By the number of unique combinations of metric name and tag values, averaged per hour over the month. Pro includes 100 per host and Enterprise 200. Above that the list price is $5 per 100 a month, and a histogram or distribution counts 5 times per combination.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much do Datadog logs cost?
&lt;/h3&gt;

&lt;p&gt;$0.10 per GB ingested, plus $1.06 to $2.50 per million indexed events depending on retention (3 to 30 days, billed annually). Indexed logs above your commitment cost 50% more. Exclusion filters lower the indexing part, which is the larger one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Datadog charge per user?
&lt;/h3&gt;

&lt;p&gt;Infrastructure Monitoring, APM and Log Management have no per-user fee. The price list has per-seat prices for On-Call and Incident Management, and per-committer prices for CI and code security products.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the high-water mark in Datadog billing?
&lt;/h3&gt;

&lt;p&gt;Datadog counts hosts every hour, drops the top 1% of hours and bills the highest remaining count. In a 30 day month that is the ninth highest hourly reading. Scale-ups that touch 8 hourly readings or fewer in the month do not raise the host count. A ninth sets it for the month.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I reduce my Datadog bill?
&lt;/h3&gt;

&lt;p&gt;Exclude logs you never search, shorten index retention, drop unused metric tags with Metrics without Limits and turn tracing off on hosts nobody traces. Then commit to your baseline usage. In the example above these steps cut the bill by 32%.&lt;/p&gt;

&lt;h2&gt;
  
  
  A recap
&lt;/h2&gt;

&lt;p&gt;If you take away 1 thing from this, let it be this:&lt;/p&gt;

&lt;p&gt;Your tags, your log filters and your busiest 9 hours set the Datadog bill.&lt;/p&gt;

&lt;p&gt;You don't NEED a consultant to fix it. The checklist above is the whole method, and a senior engineer can run it.&lt;/p&gt;

&lt;p&gt;If you'd rather have someone who has done it before look at your setup, &lt;a href="https://meteorops.com/devops-setup-for-production-free-consultation" rel="noopener noreferrer"&gt;book a free production setup consultation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;P.S. Before you delete a metric or a log, check that no SLO depends on it. I covered those in &lt;a href="https://meteorops.com/blog/slo-vs-sla" rel="noopener noreferrer"&gt;SLO vs SLA vs SLI&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>monitoring</category>
      <category>cloud</category>
      <category>sre</category>
    </item>
    <item>
      <title>SLO vs SLA vs SLI: Set Targets Before You Sign a Contract</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Fri, 13 Nov 2026 15:30:04 +0000</pubDate>
      <link>https://dev.to/meteorops/slo-vs-sla-vs-sli-set-targets-before-you-sign-a-contract-1hch</link>
      <guid>https://dev.to/meteorops/slo-vs-sla-vs-sli-set-targets-before-you-sign-a-contract-1hch</guid>
      <description>&lt;p&gt;Enterprise contracts ask for 1 number, your uptime SLA. Signing 99.9% takes 1 minute. Measuring it takes 1 quarter:&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;SLI (Service Level Indicator) = the measurement. The share of requests that went well.&lt;/p&gt;

&lt;p&gt;SLO (Service Level Objective) = the target your team sets on that measurement.&lt;/p&gt;

&lt;p&gt;SLA (Service Level Agreement) = the promise you sign with a customer, with a price for missing it.&lt;/p&gt;

&lt;p&gt;They are built in that order: measure, target, promise.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;SLI&lt;/th&gt;
&lt;th&gt;SLO&lt;/th&gt;
&lt;th&gt;SLA&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What it is&lt;/td&gt;
&lt;td&gt;A measurement&lt;/td&gt;
&lt;td&gt;An internal target&lt;/td&gt;
&lt;td&gt;A contract clause&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who owns it&lt;/td&gt;
&lt;td&gt;Engineering&lt;/td&gt;
&lt;td&gt;Engineering and product&lt;/td&gt;
&lt;td&gt;Sales, legal and the CTO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who sees it&lt;/td&gt;
&lt;td&gt;The team&lt;/td&gt;
&lt;td&gt;The company&lt;/td&gt;
&lt;td&gt;The customer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;When it is missed&lt;/td&gt;
&lt;td&gt;Nothing, it is a fact&lt;/td&gt;
&lt;td&gt;The team shifts to reliability work&lt;/td&gt;
&lt;td&gt;You pay service credits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Example&lt;/td&gt;
&lt;td&gt;99.97% of API requests succeeded in the last 30 days&lt;/td&gt;
&lt;td&gt;99.95% of API requests succeed over 30 days&lt;/td&gt;
&lt;td&gt;99.9% monthly uptime, or 10% of the monthly fee back&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rule of this article: measured &amp;gt; SLO &amp;gt; SLA.&lt;/p&gt;

&lt;p&gt;Your SLA is looser than your SLO, and your SLO is looser than what you measured. Each gap is your margin.&lt;/p&gt;

&lt;p&gt;The targets I set for a B2B SaaS product API: an SLO of 99.95% over a rolling 30 days and an SLA of 99.9% per calendar month, after 1 quarter of measuring.&lt;/p&gt;

&lt;p&gt;Below: how to define the SLI, how to pick the SLO, what an error budget buys you, what goes into the SLA clause, and the alerts that tell you before the customer does.&lt;/p&gt;

&lt;h2&gt;
  
  
  SLI, SLO and SLA are 3 layers of the same number
&lt;/h2&gt;

&lt;p&gt;Start from 1 user request.&lt;/p&gt;

&lt;p&gt;request → good or bad →&lt;br&gt;&lt;br&gt;
SLI: the share of good ones →&lt;br&gt;&lt;br&gt;
SLO: the share you aim for →&lt;br&gt;&lt;br&gt;
error budget: the bad ones you can afford →&lt;br&gt;&lt;br&gt;
SLA: the share you promise, with margin →&lt;br&gt;&lt;br&gt;
credits: what a miss costs you&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgxyzelbkjmo5dynuem81.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgxyzelbkjmo5dynuem81.webp" alt="Three stacked bands: SLI, the measurement, 99.97%; SLO, the target, 99.95%; SLA, the promise, 99.9%. An arrow beside them reads measure, target, promise." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The same number in 3 layers: the SLI you measured, the SLO you aim for, the SLA you promise. Each gap is margin.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Google's SRE book gives a 1 question test for telling an SLO from an SLA: "what happens if the SLOs aren't met?"&lt;/p&gt;

&lt;p&gt;If there is no explicit consequence, it is an SLO.&lt;/p&gt;

&lt;p&gt;If a contract names a consequence, usually money back, it is an SLA.&lt;/p&gt;

&lt;p&gt;So an SLA always contains an SLO. The reverse is optional, and for most of your services it should stay that way.&lt;/p&gt;

&lt;p&gt;SLO = a decision tool for you.&lt;/p&gt;

&lt;p&gt;SLA = a commitment to someone else.&lt;/p&gt;

&lt;p&gt;The same book defines an SLI as "a carefully defined quantitative measure of some aspect of the level of service". Carefully defined is the part that takes work, so it comes first.&lt;/p&gt;
&lt;h2&gt;
  
  
  An SLI is good events divided by all events
&lt;/h2&gt;

&lt;p&gt;SLI = good events / total events.&lt;/p&gt;

&lt;p&gt;That is the form Google's SRE workbook recommends, and it works for every kind of service:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service type&lt;/th&gt;
&lt;th&gt;SLI&lt;/th&gt;
&lt;th&gt;Good event&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API or web app&lt;/td&gt;
&lt;td&gt;Availability&lt;/td&gt;
&lt;td&gt;A request answered without a server error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API or web app&lt;/td&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;A request answered in under 300 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data pipeline&lt;/td&gt;
&lt;td&gt;Freshness&lt;/td&gt;
&lt;td&gt;A record processed within 10 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data pipeline&lt;/td&gt;
&lt;td&gt;Correctness&lt;/td&gt;
&lt;td&gt;A record with the right output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;Durability&lt;/td&gt;
&lt;td&gt;An object that can still be read&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;3 choices decide whether the number means anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Measure where the user is.&lt;/strong&gt; The workbook uses load balancer metrics because they are "closer to the user's experience" than the application server's logs. A crashed pod reports no errors, and the load balancer in front of it does&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure a real user flow.&lt;/strong&gt; Login, the core API call, checkout. A health check on /health can be green while checkout fails&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a threshold for latency.&lt;/strong&gt; "Requests under 300 ms" is a ratio you can target. An average hides the slow 1% that your biggest customer lives in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An availability SLI in Prometheus, from the request counter most HTTP frameworks already export:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sum(rate(http_requests_total{job="api",code!~"5.."}[30d]))
/
sum(rate(http_requests_total{job="api"}[30d]))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query needs 30 days of metrics, and Prometheus keeps 15 days by default, so raise the retention first. If your ingress or load balancer exports its own request counter, count from that one.&lt;/p&gt;

&lt;p&gt;If you have no metrics yet, the load balancer's access logs give you the same 2 counts. The &lt;a href="https://meteorops.com/blog/how-to-build-a-startup-observability-stack" rel="noopener noreferrer"&gt;startup observability stack&lt;/a&gt; article covers the tooling.&lt;/p&gt;

&lt;p&gt;Rule: 2 SLIs per user-facing service, availability and latency. Add a third when a customer complains about something the first 2 missed.&lt;/p&gt;

&lt;h2&gt;
  
  
  An SLO is a target, a window, and an error budget
&lt;/h2&gt;

&lt;p&gt;SLO = SLI target + time window.&lt;/p&gt;

&lt;p&gt;"99.9% of API requests succeed, over a rolling 30 days."&lt;/p&gt;

&lt;p&gt;The workbook's general-purpose window is 4 weeks, rolling. I use 30 days because the cloud SLAs you depend on count in months.&lt;/p&gt;

&lt;p&gt;The useful half of an SLO is what it leaves over.&lt;/p&gt;

&lt;p&gt;Error budget = 1 minus the SLO.&lt;/p&gt;

&lt;p&gt;At 99.9% you may fail 0.1% of requests. With 10 million requests a month, that is 10,000 failed requests you are allowed.&lt;/p&gt;

&lt;p&gt;In time, over 30 days:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SLO&lt;/th&gt;
&lt;th&gt;Error budget&lt;/th&gt;
&lt;th&gt;Full downtime it allows in 30 days&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;99%&lt;/td&gt;
&lt;td&gt;1%&lt;/td&gt;
&lt;td&gt;7 hours 12 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.5%&lt;/td&gt;
&lt;td&gt;0.5%&lt;/td&gt;
&lt;td&gt;3 hours 36 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.9%&lt;/td&gt;
&lt;td&gt;0.1%&lt;/td&gt;
&lt;td&gt;43 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.95%&lt;/td&gt;
&lt;td&gt;0.05%&lt;/td&gt;
&lt;td&gt;21 minutes 36 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.99%&lt;/td&gt;
&lt;td&gt;0.01%&lt;/td&gt;
&lt;td&gt;4 minutes 19 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.999%&lt;/td&gt;
&lt;td&gt;0.001%&lt;/td&gt;
&lt;td&gt;26 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3wtmancpmpolsv2p3cfl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3wtmancpmpolsv2p3cfl.webp" alt="Bar chart titled Error budget = 1 minus the SLO, full downtime it allows in 30 days: 99% allows 7 hours 12 minutes, 99.9% allows 43 minutes, 99.95% allows 21 minutes 36 seconds, 99.99% allows 4 minutes 19 seconds." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Each extra 9 cuts the error budget by 10: from 7 hours 12 minutes at 99% to 4 minutes 19 seconds at 99.99%.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A request-based SLO spends the same budget in failed requests, so 10 minutes down at peak costs more than 10 minutes down at 3 AM.&lt;/p&gt;

&lt;p&gt;Read the table as a staffing plan.&lt;/p&gt;

&lt;p&gt;43 minutes covers 1 incident where a person is paged, wakes up, finds the cause and rolls back.&lt;/p&gt;

&lt;p&gt;4 minutes covers none. At 99.99% every recovery has to be automatic, because the budget is gone before a human opens the laptop.&lt;/p&gt;

&lt;p&gt;5 nines leaves 26 seconds a month. (Enough time to read the alert.)&lt;/p&gt;
&lt;h3&gt;
  
  
  How to pick the number
&lt;/h3&gt;

&lt;p&gt;Google's SRE book lists 5 rules for choosing targets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"Don't pick a target based on current performance"&lt;/li&gt;
&lt;li&gt;"Keep it simple"&lt;/li&gt;
&lt;li&gt;"Avoid absolutes"&lt;/li&gt;
&lt;li&gt;"Have as few SLOs as possible"&lt;/li&gt;
&lt;li&gt;"Perfection can wait"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The workbook is blunter about the absolute: "100% reliability is the wrong target". A 100% target leaves no room for change, and change is the leading cause of outages.&lt;/p&gt;

&lt;p&gt;How I apply the 5 rules at a startup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Measure the SLI for 4 weeks before choosing anything&lt;/li&gt;
&lt;li&gt;Ask what the user needs. An internal admin tool at 99% is fine. A payments API at 99% loses customers&lt;/li&gt;
&lt;li&gt;Start the product API at 99.9% while no SLA exists, and move to 99.95% before you sign a 99.9% SLA&lt;/li&gt;
&lt;li&gt;Promise 99.99% only when failover is automatic and a drill has proven it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The opposite mistake is real too. Google's SREs found that a service running far above its SLO teaches users to depend on the extra.&lt;/p&gt;

&lt;p&gt;Their fix for Chubby, an internal lock service: in a quarter with no real failure, they take the system down on purpose.&lt;/p&gt;

&lt;p&gt;At a startup the cheaper version is to spend the budget: ship faster, run the risky migration, do the cluster upgrade in daylight.&lt;/p&gt;

&lt;p&gt;An unspent error budget = features you didn't ship.&lt;/p&gt;
&lt;h2&gt;
  
  
  Check your SLA against the SLAs you run on
&lt;/h2&gt;

&lt;p&gt;Your service sits on top of other people's promises. Dependencies in a row multiply.&lt;/p&gt;

&lt;p&gt;The AWS numbers, from its SLA pages:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;AWS service&lt;/th&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Monthly uptime in the SLA&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;EC2&lt;/td&gt;
&lt;td&gt;Instances in 2 or more availability zones&lt;/td&gt;
&lt;td&gt;99.99%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EC2&lt;/td&gt;
&lt;td&gt;A single instance&lt;/td&gt;
&lt;td&gt;99.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RDS&lt;/td&gt;
&lt;td&gt;Multi-AZ&lt;/td&gt;
&lt;td&gt;99.95%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RDS&lt;/td&gt;
&lt;td&gt;Single instance&lt;/td&gt;
&lt;td&gt;99.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Elastic Load Balancing&lt;/td&gt;
&lt;td&gt;Across 2 or more availability zones&lt;/td&gt;
&lt;td&gt;99.99%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A request that needs the load balancer, the compute and the database:&lt;/p&gt;

&lt;p&gt;99.99% × 99.99% × 99.95% = 99.93%&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwofg9qkeern1newikmtu.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwofg9qkeern1newikmtu.webp" alt="Three chain links titled Dependencies in a row multiply: load balancer 99.99% times compute 99.99% times database 99.95% equals 99.93%, what the cloud commits to." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Dependencies in a row multiply: 3 AWS SLAs of 99.99%, 99.99% and 99.95% leave 99.93%.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is what the cloud commits to before your own code fails once: the level AWS pays credits below.&lt;/p&gt;

&lt;p&gt;An SLA of 99.95% on top of it is a promise your suppliers never made to you.&lt;/p&gt;

&lt;p&gt;Run the database on a single instance and the chain drops to about 99.48%. Signing 99.9% on that setup is a bet.&lt;/p&gt;

&lt;p&gt;The provider's SLA is the floor it pays for missing. Real availability is usually higher, and your measurement is how you find out by how much.&lt;/p&gt;

&lt;p&gt;Redundancy is the lever that raises the ceiling, and it has a price. The &lt;a href="https://meteorops.com/blog/rto-vs-rpo" rel="noopener noreferrer"&gt;RTO vs RPO&lt;/a&gt; article lays out what each level costs.&lt;/p&gt;
&lt;h2&gt;
  
  
  An SLA is an SLO with a price
&lt;/h2&gt;

&lt;p&gt;An SLA clause has 6 parts. Check each one before you sign, on either side of the table:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The metric:&lt;/strong&gt; what counts as "available", and who measures it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The window:&lt;/strong&gt; usually a calendar month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The target:&lt;/strong&gt; the percentage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The exclusions:&lt;/strong&gt; scheduled maintenance, the customer's own outages, beta features, force majeure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The remedy:&lt;/strong&gt; a service credit schedule&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The claim process:&lt;/strong&gt; who has to notice, and by when&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AWS's EC2 SLA is a good model to read, because it is short:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Monthly uptime of the region&lt;/th&gt;
&lt;th&gt;Service credit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Below 99.99%, down to 99.0%&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Below 99.0%, down to 95.0%&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Below 95.0%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;2 details in it are worth copying.&lt;/p&gt;

&lt;p&gt;The remedy is a credit against future bills, 100% of that month's EC2 charge at most.&lt;/p&gt;

&lt;p&gt;The customer has to claim it: a support case, received by the end of the second billing cycle after the incident. A credit nobody claims is never paid.&lt;/p&gt;

&lt;p&gt;Which also means: if your cloud bill is large and your region had a bad month, someone on your team should be opening that case.&lt;/p&gt;
&lt;h3&gt;
  
  
  A clause to hand your lawyer
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Provider will make the Service available with a Monthly Uptime Percentage of at least 99.9%. Monthly Uptime Percentage is the share of minutes in a calendar month in which the production API, measured at Provider's load balancer, answers at least 99% of requests with a response other than a 5xx error. Minutes in which the Service is unreachable count as unavailable. Scheduled maintenance announced 72 hours ahead, failures caused by Customer's systems, beta features and force majeure events are excluded. If the Monthly Uptime Percentage falls below 99.9%, Customer may request a service credit of 10% of that month's fee, or 25% if it falls below 99.0%. Requests must be made within 30 days of the end of the month. Service credits are Customer's sole and exclusive remedy for a failure to meet this commitment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is a draft for your lawyer, with the engineering parts already in: a metric defined per minute, a named measuring point, a window, the exclusions and a remedy with a ceiling.&lt;/p&gt;

&lt;p&gt;Track it on its own dashboard. The SLA counts calendar months and the SLO counts a rolling 30 days, so the 2 numbers differ on most days.&lt;/p&gt;

&lt;p&gt;The 3 rules I hold when sales brings a contract:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SLA = SLO minus margin.&lt;/strong&gt; Google Cloud's SRE fundamentals post gives an SLA of 99.9% backed by an internal SLO of 99.95%. You can spend the whole SLO budget and still have half the SLA's budget left&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promise what a quarter of measurement has shown.&lt;/strong&gt; A number copied from a competitor's pricing page is a guess&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price the extra 9.&lt;/strong&gt; A customer who needs 99.99% is asking for a second availability zone everywhere, automatic failover and 24/7 on-call. That is a different tier with a different price&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;a href="https://meteorops.com/glossary/service-level-agreement-sla" rel="noopener noreferrer"&gt;SLA glossary entry&lt;/a&gt; has the shorter definition if you need to send one to a colleague.&lt;/p&gt;
&lt;h2&gt;
  
  
  Alert on how fast the error budget burns
&lt;/h2&gt;

&lt;p&gt;An SLO gives you the 1 alert worth waking up for: the budget is burning too fast.&lt;/p&gt;

&lt;p&gt;The workbook's definition: "Burn rate is how fast, relative to the SLO, the service consumes the error budget."&lt;/p&gt;

&lt;p&gt;Burn rate 1 = the budget lasts exactly the 30 days.&lt;/p&gt;

&lt;p&gt;Burn rate 10 = it is gone in 3 days.&lt;/p&gt;

&lt;p&gt;Burn rate 1,000 = everything is failing, and a 99.9% budget is gone in 43 minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4arh1ztcprzkwpanth0q.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4arh1ztcprzkwpanth0q.webp" alt="Line chart titled How fast the error budget burns: at burn rate 1 the budget lasts 30 days, at burn rate 10 it lasts 3 days, at burn rate 1,000 it is gone in 43 minutes." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Burn rate is the slope of the error budget: 30 days at 1, 3 days at 10, 43 minutes at 1,000.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The alert setup Google recommends for a 99.9% SLO:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Burn rate&lt;/th&gt;
&lt;th&gt;Long window&lt;/th&gt;
&lt;th&gt;Short window&lt;/th&gt;
&lt;th&gt;Budget consumed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Page&lt;/td&gt;
&lt;td&gt;14.4&lt;/td&gt;
&lt;td&gt;1 hour&lt;/td&gt;
&lt;td&gt;5 minutes&lt;/td&gt;
&lt;td&gt;2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6 hours&lt;/td&gt;
&lt;td&gt;30 minutes&lt;/td&gt;
&lt;td&gt;5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ticket&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3 days&lt;/td&gt;
&lt;td&gt;6 hours&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The long window proves the problem is real. The short window proves it is still happening, so the page stops soon after the fix.&lt;/p&gt;

&lt;p&gt;The paging rule in Prometheus, in the workbook's shorthand (0.001 is the error budget of a 99.9% SLO; for 99.95% use 0.0005):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expr: (
        job:slo_errors_per_request:ratio_rate1h{job="myjob"} &amp;gt; (14.4*0.001)
      and
        job:slo_errors_per_request:ratio_rate5m{job="myjob"} &amp;gt; (14.4*0.001)
      )
    or
      (
        job:slo_errors_per_request:ratio_rate6h{job="myjob"} &amp;gt; (6*0.001)
      and
        job:slo_errors_per_request:ratio_rate30m{job="myjob"} &amp;gt; (6*0.001)
      )
severity: page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;ratio_rate&lt;/code&gt; series is a &lt;a href="https://meteorops.com/glossary/prometheus-recording-rule" rel="noopener noreferrer"&gt;recording rule&lt;/a&gt;: errors divided by requests over that window.&lt;/p&gt;

&lt;p&gt;2 pages and 1 ticket replace the CPU and memory pages that wake people for things users never felt. Disk space and certificate expiry stay as tickets.&lt;/p&gt;

&lt;p&gt;That swap is most of the cure for &lt;a href="https://meteorops.com/blog/how-to-handle-alert-fatigue" rel="noopener noreferrer"&gt;alert fatigue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One warning for small products, with the workbook's own numbers: at 10 requests an hour, 1 failed request is a burn rate of 1,000.&lt;/p&gt;

&lt;p&gt;Its options: synthetic traffic, combining small services into 1 SLO, or lowering the SLO or lengthening its window. I start with the longer window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decide what happens when the budget runs out
&lt;/h2&gt;

&lt;p&gt;An SLO with no consequence inside the company is a dashboard.&lt;/p&gt;

&lt;p&gt;The consequence is an error budget policy, agreed while everyone is calm. Google publishes its example, and 3 lines carry it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Budget spent:&lt;/strong&gt; "we will halt all changes and releases other than P0 issues or security fixes until the service is back within its SLO"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 incident eats more than 20% of the budget:&lt;/strong&gt; the team must conduct a &lt;a href="https://meteorops.com/glossary/postmortem" rel="noopener noreferrer"&gt;postmortem&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The teams disagree:&lt;/strong&gt; "the issue should be escalated to the CTO to make a decision"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The startup version I use fits in 4 lines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Budget left: ship whenever you want&lt;/li&gt;
&lt;li&gt;Half the budget gone in the first week: the on-call engineer reviews every deploy until the window recovers&lt;/li&gt;
&lt;li&gt;Budget spent: the next sprint's first items are reliability work&lt;/li&gt;
&lt;li&gt;1 incident over 20% of the budget: a written postmortem with 1 fix that gets done&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why does a CTO want this? Because "should we slow down and fix reliability" stops being an argument between product and engineering.&lt;/p&gt;

&lt;p&gt;The number answers it every Monday.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://meteorops.com/glossary/error-budget" rel="noopener noreferrer"&gt;error budget&lt;/a&gt; is the only reliability metric I know that tells a team when to go faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SLO document, on 1 page
&lt;/h2&gt;

&lt;p&gt;1 page per user-facing service, under 8 headings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Service and user flow:&lt;/strong&gt; what the user is doing ("call the public API")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLI:&lt;/strong&gt; the good event, the total event, and the query that counts both&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLO:&lt;/strong&gt; the target and the window&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error budget:&lt;/strong&gt; in requests and in minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alerts:&lt;/strong&gt; the burn rates that page and the one that opens a ticket&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy:&lt;/strong&gt; what happens at half spent and at fully spent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External SLA:&lt;/strong&gt; the number in contracts, and the margin to the SLO&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Owner and review date:&lt;/strong&gt; a name, and a quarterly check that the target still matches what users need&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Heading 7 is the one sales should read before the next enterprise call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes I keep seeing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An SLA signed before any SLI exists:&lt;/strong&gt; the first measurement arrives with the customer's complaint&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLA equal to the SLO:&lt;/strong&gt; every internal miss is a contract breach&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The SLO copied from last month's graph:&lt;/strong&gt; current performance is where you start measuring, and the user's need is what sets the target&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A 100% target:&lt;/strong&gt; no deploy is safe under it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uptime measured by a ping on /health:&lt;/strong&gt; the health check passes while the checkout fails&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Average latency as the SLI:&lt;/strong&gt; the slowest 1% is invisible in it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;15 SLOs per service:&lt;/strong&gt; nobody can say which one matters during an incident&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;99.99% promised on a single database instance:&lt;/strong&gt; the supplier's own SLA for it is 99.5%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud credits nobody claims:&lt;/strong&gt; the provider waits for your support case&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;p&gt;Always:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define 2 SLIs per user-facing service: availability and latency, as good events over total events&lt;/li&gt;
&lt;li&gt;Measure at the load balancer, on a real user flow&lt;/li&gt;
&lt;li&gt;Measure for 4 weeks before setting a target&lt;/li&gt;
&lt;li&gt;Set 1 SLO per SLI with a 30 day window, and write the error budget in minutes and in requests&lt;/li&gt;
&lt;li&gt;Multiply your dependencies' SLAs and check the SLA you sign sits under the result&lt;/li&gt;
&lt;li&gt;Page on burn rate 14.4 and 6, ticket on burn rate 1&lt;/li&gt;
&lt;li&gt;Write the error budget policy before the first incident&lt;/li&gt;
&lt;li&gt;Sign an SLA only with a quarter of measurements behind it, looser than the SLO&lt;/li&gt;
&lt;li&gt;Put exclusions, a credit schedule, a claim deadline and a sole remedy line in every SLA&lt;/li&gt;
&lt;li&gt;Review each SLO every quarter with product in the room&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What's the difference between SLOs and SLAs?
&lt;/h3&gt;

&lt;p&gt;An SLO is an internal target your team sets for a service. An SLA is a contract with a customer that includes a consequence, usually service credits, for missing a target. Set the SLO tighter than the SLA, so you find out about a problem before it costs you money.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is an SLO part of an SLA?
&lt;/h3&gt;

&lt;p&gt;Yes. Every SLA contains at least 1 objective, the number being promised, plus the consequence for missing it. Most SLOs have no SLA around them: they exist so the team can decide between shipping and fixing.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between SLI, SLO and SLA?
&lt;/h3&gt;

&lt;p&gt;The SLI is the measurement (99.97% of requests succeeded). The SLO is the target on it (99.95% over 30 days). The SLA is the promise to a customer (99.9% monthly, or credits). Measure, target, promise, in that order.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is an example of an SLO?
&lt;/h3&gt;

&lt;p&gt;"99.9% of requests to the public API return a successful response, measured at the load balancer over a rolling 30 days." A latency SLO for the same service: "95% of requests complete in under 300 ms over a rolling 30 days."&lt;/p&gt;

&lt;h3&gt;
  
  
  What is an error budget?
&lt;/h3&gt;

&lt;p&gt;1 minus the SLO. A 99.9% SLO leaves a budget of 0.1%: about 43 minutes of full downtime in 30 days, or 10,000 failed requests out of 10 million. While budget remains the team ships; when it is spent the team works on reliability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which comes first, the SLO or the SLA?
&lt;/h3&gt;

&lt;p&gt;The SLO, with the SLI before it. Run the SLO for a quarter, see what you achieve, then offer an SLA with margin below it. An SLA signed first means the customer's contract is setting your engineering priorities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does every service need an SLA?
&lt;/h3&gt;

&lt;p&gt;No. Internal services and free tiers run on SLOs alone. Sign an SLA when a paying customer asks for one, and only for the service that customer uses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is 99.9% uptime good?
&lt;/h3&gt;

&lt;p&gt;For most B2B SaaS products, yes. It allows 43 minutes of downtime in 30 days, which a small on-call team can meet with 1 region and 2 availability zones. 99.99% allows 4 minutes and needs automatic failover everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who owns the SLO?
&lt;/h3&gt;

&lt;p&gt;The team that runs the service owns the measurement and the alerts. Product agrees to the target, because the target decides how much time goes to features. The CTO owns the tie-break, and signs off on any SLA built on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  A recap
&lt;/h2&gt;

&lt;p&gt;If you take away 1 thing, let it be this: measured &amp;gt; SLO &amp;gt; SLA.&lt;/p&gt;

&lt;p&gt;Measure the SLI where the user is. Set the SLO from what the user needs.&lt;/p&gt;

&lt;p&gt;Spend the error budget on shipping. Page on the burn rate.&lt;/p&gt;

&lt;p&gt;Sign the SLA last, with margin.&lt;/p&gt;

&lt;p&gt;You don't NEED a DevOps expert for the first SLO. A load balancer log, a spreadsheet and 4 weeks get you the first honest number.&lt;/p&gt;

&lt;p&gt;If you would rather set it up with a team that has worked with 200+ companies, &lt;a href="https://meteorops.com/devops-setup-for-production-free-consultation" rel="noopener noreferrer"&gt;book a free production setup consultation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;P.S. The on-call rotation that answers those 2 pages is its own design problem. I wrote about it in &lt;a href="https://meteorops.com/blog/how-to-design-on-call-before-you-hire-sre" rel="noopener noreferrer"&gt;how to design on-call before you hire an SRE&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>sre</category>
      <category>startup</category>
      <category>management</category>
    </item>
    <item>
      <title>DevOps as a Service: What It Is, Costs, and When to Use It</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Thu, 12 Nov 2026 07:30:12 +0000</pubDate>
      <link>https://dev.to/meteorops/devops-as-a-service-what-it-is-costs-and-when-to-use-it-214f</link>
      <guid>https://dev.to/meteorops/devops-as-a-service-what-it-is-costs-and-when-to-use-it-214f</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide was written by &lt;a href="https://meteorops.com/team/arthur-azrieli" rel="noopener noreferrer"&gt;Arthur Azrieli&lt;/a&gt;, CTO at MeteorOps, and first published on the &lt;a href="https://meteorops.com/blog/devops-team-vs-devops-as-a-service" rel="noopener noreferrer"&gt;MeteorOps blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;DevOps as a Service (DaaS) means an outside team of DevOps engineers builds and runs your delivery and cloud operations for a recurring fee: CI/CD pipelines, infrastructure as code, Kubernetes or other runtimes, monitoring, security baselines and cost control. You get a team's skills for less than a team's payroll. In exchange, you have to manage the ownership, access and exit terms carefully.&lt;/p&gt;

&lt;p&gt;It beats hiring when your DevOps workload is real but not big enough for two or three full-time specialists. It also fits when you need senior skills faster than you can recruit them, or when one engineer is currently the only person who understands production. It loses to hiring when infrastructure is your product, when the work is constant and deep enough to keep a team busy, or when nobody inside the company can own decisions about the platform.&lt;/p&gt;

&lt;p&gt;This guide is for founders, CTOs and engineering leaders deciding how to cover DevOps. It covers what DaaS actually includes, the delivery models providers sell under that name, how pricing works and how to compare it with the true cost of hiring, a decision checklist, contract safeguards, and how to run the first 90 days.&lt;/p&gt;

&lt;h2&gt;
  
  
  What DevOps as a Service actually includes
&lt;/h2&gt;

&lt;p&gt;"DevOps as a Service" gets used for three different things, which is why the search results feel contradictory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A managed engineering service.&lt;/strong&gt; A provider's engineers work on your cloud accounts, repositories and pipelines on an ongoing basis. This is what most buyers mean, and what this guide is about.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A hosted toolchain.&lt;/strong&gt; GitHub, GitLab, Azure DevOps or AWS developer tools sold as SaaS. Useful, but that is buying tools, not getting DevOps done.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A platform product.&lt;/strong&gt; An internal developer platform or "platform as a service" that hides infrastructure behind a portal. It reduces DevOps work for product teams, but someone still has to run it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A serious DaaS engagement usually covers these workstreams. Most companies need four or five of them, not all eight:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workstream&lt;/th&gt;
&lt;th&gt;What the provider does&lt;/th&gt;
&lt;th&gt;What you should get to keep&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cloud foundation&lt;/td&gt;
&lt;td&gt;Account structure, networking, identity and access, landing zone, environments&lt;/td&gt;
&lt;td&gt;Infrastructure as code in your repositories, an access model diagram&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure as code&lt;/td&gt;
&lt;td&gt;Terraform or OpenTofu modules, state management, review workflow&lt;/td&gt;
&lt;td&gt;Modules your engineers can read and change through pull requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD&lt;/td&gt;
&lt;td&gt;Build, test and deploy pipelines, environment promotion, rollback&lt;/td&gt;
&lt;td&gt;Pipeline definitions in your repositories, a documented release process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;Kubernetes, ECS, Cloud Run or VM operations, upgrades, autoscaling&lt;/td&gt;
&lt;td&gt;Upgrade runbooks, a version and support calendar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;Metrics, logs, traces, dashboards, alert rules&lt;/td&gt;
&lt;td&gt;Alerts that page the right owner, dashboards per service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliability and on-call&lt;/td&gt;
&lt;td&gt;Incident response, postmortems, backup and restore testing&lt;/td&gt;
&lt;td&gt;Runbooks, tested restore procedures, an escalation policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security and compliance&lt;/td&gt;
&lt;td&gt;Secrets management, least privilege, vulnerability scanning, audit evidence&lt;/td&gt;
&lt;td&gt;Evidence that maps to your SOC 2 or ISO 27001 controls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost control&lt;/td&gt;
&lt;td&gt;Tagging, rightsizing, commitments, budgets and alerts&lt;/td&gt;
&lt;td&gt;A cost report your finance team can read, owners per cost line&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Look at the last column. It is the real test of a DaaS provider. The fee buys work, but the value you keep is the code, documentation and operating habits that stay when the engagement ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four ways to get DevOps covered
&lt;/h2&gt;

&lt;p&gt;DaaS is one of four models. The difference that matters most is who owns the outcome and who directs the work day to day.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;In-house DevOps team&lt;/th&gt;
&lt;th&gt;DevOps as a Service&lt;/th&gt;
&lt;th&gt;Staff augmentation&lt;/th&gt;
&lt;th&gt;Project consulting&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who directs the work&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;Shared: you set priorities, the provider plans and executes&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;The provider, against a defined goal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who owns production outcomes&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;Shared, defined in the contract&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;You, after handover&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical commitment&lt;/td&gt;
&lt;td&gt;Permanent headcount&lt;/td&gt;
&lt;td&gt;Monthly, ongoing&lt;/td&gt;
&lt;td&gt;Monthly per engineer&lt;/td&gt;
&lt;td&gt;Fixed scope and timeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time to first useful work&lt;/td&gt;
&lt;td&gt;Months (hiring plus ramp-up)&lt;/td&gt;
&lt;td&gt;Days to weeks&lt;/td&gt;
&lt;td&gt;Weeks&lt;/td&gt;
&lt;td&gt;Weeks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Breadth of skills&lt;/td&gt;
&lt;td&gt;Whatever you hired&lt;/td&gt;
&lt;td&gt;A bench of specialists behind your main engineer&lt;/td&gt;
&lt;td&gt;One person's skills&lt;/td&gt;
&lt;td&gt;Whatever the project needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Main risk&lt;/td&gt;
&lt;td&gt;Slow hiring, single points of failure&lt;/td&gt;
&lt;td&gt;Knowledge staying with the provider&lt;/td&gt;
&lt;td&gt;You still need to manage and review the work&lt;/td&gt;
&lt;td&gt;Handover to nobody&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Large, constant platform work&lt;/td&gt;
&lt;td&gt;Startups and scale-ups without a full DevOps team&lt;/td&gt;
&lt;td&gt;A known backlog and a capacity gap&lt;/td&gt;
&lt;td&gt;A migration or a one-off build&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fquaybe02mv6g5rl465cg.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fquaybe02mv6g5rl465cg.webp" alt="Comparison of four ways to get DevOps covered: an in-house DevOps team, DevOps as a Service, staff augmentation and project consulting, showing who directs the work, who owns outcomes and the time to first useful work for each." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;DevOps as a Service is the only model where direction and ownership are shared, and it starts in days to weeks.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Many companies combine them: DaaS to stabilize and build the foundation, then one internal hire who takes over day-to-day ownership while the provider stays on for depth and coverage. If the staff augmentation column looks closer to what you need, read &lt;a href="https://meteorops.com/blog/how-to-choose-a-staff-augmentation-company" rel="noopener noreferrer"&gt;how to choose a staff augmentation company&lt;/a&gt;. For a project with a clear end, read &lt;a href="https://meteorops.com/blog/how-to-choose-a-devops-consulting-service" rel="noopener noreferrer"&gt;how to choose a DevOps consulting service&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When DevOps as a Service beats hiring
&lt;/h2&gt;

&lt;p&gt;DaaS is usually the better choice when most of these are true:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The workload is real but uneven.&lt;/strong&gt; Some months bring a migration, a compliance audit or a Kubernetes upgrade. Other months are mostly maintenance. A full-time hire is either overloaded or underused.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You need breadth one person cannot have.&lt;/strong&gt; Networking, Kubernetes internals, Terraform design, database operations, security and cost optimization rarely sit in one head.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Production depends on one person.&lt;/strong&gt; If your only infrastructure engineer goes on holiday and deploys stop, you have a bus factor of one. A provider gives you coverage and a second pair of eyes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hiring is slow or risky.&lt;/strong&gt; Senior DevOps engineers are hard to assess if nobody on your team is senior in DevOps. A bad hire with production access is expensive to undo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You are early.&lt;/strong&gt; Teams of roughly 5 to 40 engineers usually do not need a dedicated platform team yet, but they do need production-grade foundations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When hiring wins
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Infrastructure is part of what you sell (a data platform, a developer tool, a hosting product).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The work is constant and deep enough to keep two or more specialists busy all year.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Regulation or customer contracts prevent outside parties from accessing production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You are building a platform team that will serve many product teams, and you want it to grow with the company.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even then, a provider often helps for the first months: setting up the foundations, helping you interview candidates and handing over to the new team. If you are unsure how much DevOps work you actually have, &lt;a href="https://meteorops.com/blog/calculating-your-companys-required-devops-capacity" rel="noopener noreferrer"&gt;estimate your required DevOps capacity&lt;/a&gt; before deciding. The &lt;a href="https://meteorops.com/blog/how-to-build-a-devops-team" rel="noopener noreferrer"&gt;guide to building a DevOps team&lt;/a&gt; covers the hiring path.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much DevOps as a Service costs
&lt;/h2&gt;

&lt;p&gt;Providers rarely publish prices, and the ones that do are not comparable, because "a plan" can mean ten hours or a full-time engineer. What you can compare is the pricing model and what it includes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pricing model&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;th&gt;Watch for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Monthly hours plan&lt;/td&gt;
&lt;td&gt;A fixed block of engineering hours per month, often with tiers&lt;/td&gt;
&lt;td&gt;Ongoing work with uneven demand&lt;/td&gt;
&lt;td&gt;Unused-hour expiry, response times outside the plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dedicated engineer&lt;/td&gt;
&lt;td&gt;One or more named engineers at a monthly rate&lt;/td&gt;
&lt;td&gt;Steady workload, deep context&lt;/td&gt;
&lt;td&gt;Whether a senior backs up the engineer, cover during leave&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Managed service with service levels&lt;/td&gt;
&lt;td&gt;A fee per environment or service, with uptime and response commitments&lt;/td&gt;
&lt;td&gt;Operations you never want to think about&lt;/td&gt;
&lt;td&gt;What counts as "in scope", penalties that are only credits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixed-price project plus retainer&lt;/td&gt;
&lt;td&gt;A defined build, then a smaller monthly plan to run it&lt;/td&gt;
&lt;td&gt;Foundations, migrations&lt;/td&gt;
&lt;td&gt;Change requests, who fixes defects after go-live&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pay per hour&lt;/td&gt;
&lt;td&gt;Billed monthly for hours worked&lt;/td&gt;
&lt;td&gt;Advisory work, small or unpredictable needs&lt;/td&gt;
&lt;td&gt;Availability when you need someone urgently&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Compare it with the real cost of hiring
&lt;/h3&gt;

&lt;p&gt;The fair comparison is not a provider's monthly fee against a salary. It is against the full cost of covering the same work in-house:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Loaded salary.&lt;/strong&gt; The US Bureau of Labor Statistics puts the median software developer wage at $135,980 (&lt;a href="https://www.bls.gov/ooh/computer-and-information-technology/software-developers.htm" rel="noopener noreferrer"&gt;May 2025&lt;/a&gt;). Experienced DevOps and platform engineers are often above that median. Wages are about 70% of total employer compensation cost in US private industry (&lt;a href="https://www.bls.gov/news.release/ecec.nr0.htm" rel="noopener noreferrer"&gt;BLS, June 2026&lt;/a&gt;), so a $136,000 salary is roughly $194,000 in total cost before recruiting, equipment and tooling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recruiting and ramp-up.&lt;/strong&gt; Recruiter fees, interview time from your senior engineers, and the months before a new hire is fully productive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Coverage.&lt;/strong&gt; One engineer is not on-call coverage. Real coverage for production needs at least two people who can respond, or an escalation path to someone outside.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Breadth gaps.&lt;/strong&gt; The specialist work your hire cannot do still needs a consultant, so add a buffer for it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost of mistakes.&lt;/strong&gt; Outages, security incidents and cloud waste from missing experience are real costs, even if they never appear in a budget line.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu3b2la0uxtsm44uvlnzi.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu3b2la0uxtsm44uvlnzi.webp" alt="Bar chart showing a $136,000 salary becoming about $194,000 in total cost because wages are about 70% of total cost, with recruiting and ramp-up, coverage, breadth gaps and cost of mistakes stacked on top as the real cost to compare." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Compare a provider's quote with the full stack of hiring costs, not with the salary alone.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Put a one-year number on each line, then ask providers to quote the same scope. If the provider costs more but removes the coverage gap and the breadth gap, it can still be the cheaper option. If you have constant work for two engineers, hiring usually wins on cost within a year or two. To see how MeteorOps structures engagements, see the &lt;a href="https://meteorops.com/plans-pricing" rel="noopener noreferrer"&gt;plans and pricing page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision checklist: DaaS, hire, or both
&lt;/h2&gt;

&lt;p&gt;Answer these honestly. Each "yes" in the left group points toward DevOps as a Service, and each "yes" in the right group points toward hiring.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Points to DevOps as a Service&lt;/th&gt;
&lt;th&gt;Points to hiring&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fewer than about 40 engineers, no platform team yet&lt;/td&gt;
&lt;td&gt;Several product teams that need a shared platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workload swings with launches, audits and migrations&lt;/td&gt;
&lt;td&gt;Constant workload for two or more specialists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Only one person understands production today&lt;/td&gt;
&lt;td&gt;You already have DevOps people who need reinforcement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need results this quarter&lt;/td&gt;
&lt;td&gt;You can wait three to six months for a hire to ramp up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need several specialties occasionally&lt;/td&gt;
&lt;td&gt;You need one specialty all the time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nobody internal can assess DevOps candidates&lt;/td&gt;
&lt;td&gt;A senior engineer can run the hiring process&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A mixed result is common and usually means "both": a provider now, and a plan to hire one owner who works alongside them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flddx5vtn8g3use58b9bb.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flddx5vtn8g3use58b9bb.webp" alt="Balance scale weighing signals that point to DevOps as a Service, such as fewer than about 40 engineers and workload swings, against signals that point to hiring, such as several product teams and constant work for two or more, with a mixed result meaning a provider now and one owner later." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Count the yes answers on each side; a mixed result usually means using both.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What good DevOps as a Service looks like in practice
&lt;/h2&gt;

&lt;p&gt;These are the signals that a provider runs DaaS as engineering, not as a ticket desk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Everything lands in your repositories.&lt;/strong&gt; Terraform, pipeline files, Helm charts and runbooks live in your Git organization and go through your pull request reviews.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Access is personal and least privilege.&lt;/strong&gt; Each engineer has their own identity through your identity provider or AWS IAM Identity Center. Nobody shares root credentials or long-lived access keys.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A named lead engineer, with seniors behind them.&lt;/strong&gt; You know who works on your systems, and design reviews involve someone more senior than the person doing the work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Visible work.&lt;/strong&gt; A shared backlog, short written updates, and decisions recorded where your team can find them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Measured outcomes.&lt;/strong&gt; Progress is tracked with delivery metrics such as the five &lt;a href="https://dora.dev/guides/dora-metrics/" rel="noopener noreferrer"&gt;DORA metrics&lt;/a&gt; (change lead time, deployment frequency, failed deployment recovery time, change fail rate and deployment rework rate), plus cloud cost and incident trends. Hours logged and tickets closed do not count as outcomes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Your team gets more capable.&lt;/strong&gt; Your developers can deploy, read dashboards and handle common incidents without asking the provider.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contract safeguards before you sign
&lt;/h2&gt;

&lt;p&gt;DaaS contracts fail at the edges: who owns what, how fast someone responds, and how you leave. Check these clauses:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Clause&lt;/th&gt;
&lt;th&gt;What to look for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Intellectual property&lt;/td&gt;
&lt;td&gt;All code, configuration and documentation created for you belongs to you, with no license fees to keep using it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access and credentials&lt;/td&gt;
&lt;td&gt;Your identity provider, individual accounts, removal on exit, no provider-owned accounts in your production path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope and response times&lt;/td&gt;
&lt;td&gt;What is included, what is extra, and response times for production incidents in writing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Named people&lt;/td&gt;
&lt;td&gt;Who your lead engineer is, notice before they change, and how a replacement gets onboarded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security and confidentiality&lt;/td&gt;
&lt;td&gt;Handling of secrets and customer data, background checks, and support for your audits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exit and handover&lt;/td&gt;
&lt;td&gt;A handover period, final documentation, access removal and a reasonable notice period&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commitment&lt;/td&gt;
&lt;td&gt;Minimum term, how to scale hours up or down, and what happens to unused hours&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A provider that resists the exit clause is telling you how the relationship will end. A good one plans for its own replacement from the first week.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first 90 days of a DevOps as a Service engagement
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Days 1 to 14: access and assessment.&lt;/strong&gt; Set up individual access, review cloud accounts, repositories, pipelines, monitoring, incident history and the cloud bill. The output should be a written list of risks ranked by impact, not a new architecture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Days 15 to 45: reduce the biggest risks.&lt;/strong&gt; Typical first fixes: backups that are actually restorable, removing shared admin access, moving unmanaged production resources into infrastructure as code, alerts on customer-facing symptoms, and a rollback path for deployments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Days 46 to 75: speed up delivery.&lt;/strong&gt; Faster, more reliable pipelines, preview or staging environments that match production, and fewer manual release steps.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Days 76 to 90: review and plan.&lt;/strong&gt; Compare the delivery metrics, incident count and cloud spend against day 1. Agree on the next quarter's priorities and adjust the plan size up or down.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqe4ka0bo7dkovebogsfh.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqe4ka0bo7dkovebogsfh.webp" alt="Timeline of the first 90 days of a DevOps as a Service engagement: days 1 to 14 access and assessment, days 15 to 45 reduce the biggest risks, days 46 to 75 speed up delivery, days 76 to 90 review and plan." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A good engagement starts with a ranked risk list and earns the right to speed things up.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If the first two weeks produce a sales proposal for a large rebuild instead of a ranked risk list, slow down. A &lt;a href="https://meteorops.com/assessments/devops-maturity" rel="noopener noreferrer"&gt;DevOps maturity assessment&lt;/a&gt; is a cheap way to get a baseline before you commit to anything larger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes with DevOps as a Service
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Outsourcing ownership along with the work.&lt;/strong&gt; Someone inside the company still has to make product and risk decisions about production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Treating the provider as a ticket queue.&lt;/strong&gt; If every change waits for a ticket to be picked up, delivery slows down. Ask for self-service paths for your developers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Letting infrastructure live in the provider's accounts.&lt;/strong&gt; Cloud accounts, domains, repositories and secrets stores should be yours from the start.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Buying tools before defining problems.&lt;/strong&gt; New platforms do not fix unclear ownership or missing runbooks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No exit plan.&lt;/strong&gt; If you could not switch providers in a month, you are locked in, whatever the contract says.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is DevOps as a Service?
&lt;/h3&gt;

&lt;p&gt;DevOps as a Service is an outsourced model where an external team builds and operates your delivery pipelines, cloud infrastructure, monitoring and related practices for an ongoing fee. Unlike buying DevOps tools, you are buying engineers' time and expertise, delivered inside your own accounts and repositories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is DevOps as a Service the same as managed DevOps services?
&lt;/h3&gt;

&lt;p&gt;Mostly, yes. "Managed DevOps services" usually puts more emphasis on running existing systems against service levels, while "DevOps as a Service" also covers building new foundations. In practice, check the scope and response terms rather than the label.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much does DevOps as a Service cost?
&lt;/h3&gt;

&lt;p&gt;It depends on the pricing model (hours plan, dedicated engineer, managed service or project) and the scope. Compare quotes against the full one-year cost of hiring: loaded salary, recruiting, ramp-up, on-call coverage and the specialist help a single hire would still need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is DevOps as a Service worth it for a small team?
&lt;/h3&gt;

&lt;p&gt;For teams without a dedicated DevOps engineer, it usually is, because one hire cannot cover all the specialties or provide on-call coverage alone. It is less attractive if your workload is small enough for a few hours of advice a month, or large and constant enough for two full-time hires.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can a DevOps as a Service provider work alongside our in-house engineers?
&lt;/h3&gt;

&lt;p&gt;Yes, and that is often the best setup. The provider brings depth and coverage, while your engineers keep product context and ownership. Make sure work goes through the same repositories, reviews and backlog.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the risks of DevOps as a Service?
&lt;/h3&gt;

&lt;p&gt;The main risks are knowledge staying with the provider, broad access to production, and lock-in through provider-owned accounts or tools. Clear IP ownership, individual least-privilege access, documentation in your repositories and a written exit plan reduce all three.&lt;/p&gt;

&lt;h3&gt;
  
  
  How fast can a DevOps as a Service team start?
&lt;/h3&gt;

&lt;p&gt;A good provider can start within days of signing, once access is granted. Expect a short assessment first. Visible improvements usually come within the first month, and bigger changes such as migrations take longer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;DevOps as a Service gives a startup senior DevOps coverage without building a team: foundations, pipelines, monitoring, security and cost control, delivered in your own accounts. Choose it when the work is real but uneven, when you need breadth and coverage, or when production depends on one person. Hire when infrastructure is your product or the work is constant. Either way, keep ownership, access and the exit plan on your side.&lt;/p&gt;

&lt;p&gt;If you want senior engineers to take on your DevOps work this way, see how &lt;a href="https://meteorops.com/services/devops-outsourcing" rel="noopener noreferrer"&gt;MeteorOps DevOps outsourcing&lt;/a&gt; works.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>startup</category>
      <category>management</category>
      <category>leadership</category>
    </item>
    <item>
      <title>Observability Stack for Startups: What to Run at 5, 20 and 100 Engineers</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Wed, 11 Nov 2026 07:30:03 +0000</pubDate>
      <link>https://dev.to/meteorops/observability-stack-for-startups-what-to-run-at-5-20-and-100-engineers-14ai</link>
      <guid>https://dev.to/meteorops/observability-stack-for-startups-what-to-run-at-5-20-and-100-engineers-14ai</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide was written by &lt;a href="https://meteorops.com/team/michael-zion" rel="noopener noreferrer"&gt;Michael Zion&lt;/a&gt;, CEO at MeteorOps, and first published on the &lt;a href="https://meteorops.com/blog/how-to-build-a-startup-observability-stack" rel="noopener noreferrer"&gt;MeteorOps blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;A five-person startup should start with error tracking, structured logs, the four golden signals (latency, traffic, errors, saturation) for each user-facing service, uptime checks, and three or four symptom-based alerts, all on one managed platform. Add distributed tracing with OpenTelemetry once requests cross several services. Self-hosting becomes worth it only when the bill outgrows a platform engineer's time.&lt;/p&gt;

&lt;p&gt;A startup observability stack should answer three questions quickly: what is broken, who is affected, and what changed recently. It does not mean buying the biggest platform or instrumenting every function on day one. It means collecting enough signals to debug production, often Kubernetes, serverless jobs, managed databases and queues, without tribal knowledge or emergency SSH sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to run at 5, 20 and 100 engineers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Signals to have&lt;/th&gt;
&lt;th&gt;Typical tooling&lt;/th&gt;
&lt;th&gt;Who owns it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;About 5 engineers, one or two services&lt;/td&gt;
&lt;td&gt;Error tracking, structured logs, golden-signal dashboards, uptime checks, 3 to 5 alerts routed to one channel or pager&lt;/td&gt;
&lt;td&gt;One managed platform on a free or entry tier (Grafana Cloud, Datadog, or your cloud's native monitoring) plus an error tracker such as Sentry&lt;/td&gt;
&lt;td&gt;Whoever is on call, with one engineer setting conventions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;About 20 engineers, several services and workers&lt;/td&gt;
&lt;td&gt;Add OpenTelemetry tracing at service boundaries, deploy markers, queue and database dashboards, an on-call rotation, alert runbooks&lt;/td&gt;
&lt;td&gt;Same platform on a paid tier, OpenTelemetry Collector in the cluster, log retention and sampling rules&lt;/td&gt;
&lt;td&gt;A named owner for standards, usually in a platform or DevOps role&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;About 100 engineers, many teams&lt;/td&gt;
&lt;td&gt;SLOs per service, per-team dashboards and alert routing, cost allocation, trace sampling strategy&lt;/td&gt;
&lt;td&gt;Either a commercial platform under negotiated pricing or a self-hosted stack (Prometheus or Mimir, Loki, Tempo, Grafana) run by a platform team&lt;/td&gt;
&lt;td&gt;A platform team that treats observability as an internal product&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What it costs: Grafana Cloud vs Datadog vs self-hosted
&lt;/h2&gt;

&lt;p&gt;List prices from the vendors' pricing pages as of October 2026. Real bills depend on hosts, active series, log volume and retention, so use these to compare shapes, not as quotes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Grafana Cloud&lt;/th&gt;
&lt;th&gt;Datadog&lt;/th&gt;
&lt;th&gt;Self-hosted LGTM (Loki, Grafana, Tempo, Mimir or Prometheus)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;td&gt;10k metric series, 50 GB logs, 50 GB traces, 14-day retention, 3 users&lt;/td&gt;
&lt;td&gt;Infrastructure only: up to 5 hosts, 1-day metric retention&lt;/td&gt;
&lt;td&gt;Software is free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paid entry&lt;/td&gt;
&lt;td&gt;Pro: $19 per month platform fee, same included usage, then pay as you go&lt;/td&gt;
&lt;td&gt;Infrastructure Pro: $15 per host per month billed annually ($18 on-demand)&lt;/td&gt;
&lt;td&gt;Compute and storage for the stack, often a few hundred dollars a month at startup scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metrics&lt;/td&gt;
&lt;td&gt;From $6.50 per 1k active series&lt;/td&gt;
&lt;td&gt;Included per host; custom metrics billed separately&lt;/td&gt;
&lt;td&gt;Storage and memory grow with series count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logs&lt;/td&gt;
&lt;td&gt;From about $0.55 per GB (process, write and retain combined)&lt;/td&gt;
&lt;td&gt;$0.10 per GB ingested, plus $1.70 per million events indexed for 15 days&lt;/td&gt;
&lt;td&gt;Object storage, cheap to keep&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Traces / APM&lt;/td&gt;
&lt;td&gt;Same per-GB pricing as logs&lt;/td&gt;
&lt;td&gt;APM from $31 per host per month billed annually&lt;/td&gt;
&lt;td&gt;Object storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hidden cost&lt;/td&gt;
&lt;td&gt;High-cardinality labels inflate series&lt;/td&gt;
&lt;td&gt;Per-host and indexing costs grow with every node and noisy log line&lt;/td&gt;
&lt;td&gt;Engineer time: upgrades, scaling, on-call for the monitoring itself&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sources: &lt;a href="https://grafana.com/pricing/" rel="noopener noreferrer"&gt;Grafana Cloud pricing&lt;/a&gt; and &lt;a href="https://www.datadoghq.com/pricing/" rel="noopener noreferrer"&gt;Datadog pricing&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the failures you need to diagnose
&lt;/h2&gt;

&lt;p&gt;Tool selection gets messy when teams begin with vendor feature matrices. Start with the incidents you expect to handle instead. A payments API returning intermittent 500s, a background worker falling behind its queue, a database connection pool saturating after a traffic spike, or a canary release increasing latency in one region all need different signals. Metrics are best for spotting trends and triggering alerts, logs explain discrete events, traces connect work across services, and deploy or configuration events show what changed. Mapping those failure modes first helps you decide where deep instrumentation is worth it and where a simple log line, counter, or managed cloud metric is enough.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs5famsdzxvw7h4qkqjq3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs5famsdzxvw7h4qkqjq3.webp" alt="Four cards showing what each observability signal is for: metrics spot trends and trigger alerts, logs explain discrete events, traces connect work across services, and deploy and config events show what changed." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Map the failures you expect first, then pick the signal that answers each one.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For most startups, the first observability goals should be practical, boring, and tied to production outcomes. Prioritize the checks that shorten incidents and protect user experience before you chase perfect coverage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Find customer-impacting issues fast.&lt;/strong&gt; The team should know when users are seeing elevated error rates, slow requests, failed jobs, or broken workflows. Alerts should include enough context to point to a likely service, dependency, tenant, region, or recent deploy instead of merely announcing that “something is down.”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Connect symptoms to recent changes.&lt;/strong&gt; Deployments, configuration changes, feature flags, and infrastructure updates should be visible during incident review.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debug without direct server access.&lt;/strong&gt; Engineers should not need to SSH into machines or manually inspect containers to understand production behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Support on-call without constant noise.&lt;/strong&gt; Alerts should point to real action, not every small fluctuation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep costs predictable.&lt;/strong&gt; Observability data can grow quickly, especially logs and high-cardinality metrics.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps the stack tied to operational needs instead of tool sprawl. If you are still deciding how your engineering ownership model should work, it can help to define responsibilities early. A clear team model, like the one outlined in &lt;a href="https://www.meteorops.com/blog/how-to-build-a-devops-team" rel="noopener noreferrer"&gt;how to build a DevOps team&lt;/a&gt;, makes observability easier to operate because someone owns the standards, not just the dashboard links.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build around the four core signal types
&lt;/h2&gt;

&lt;p&gt;A useful observability stack usually combines logs, metrics, traces, and alerts. Each signal answers a different kind of question. Treating one as a replacement for all the others usually creates blind spots.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logs
&lt;/h3&gt;

&lt;p&gt;Logs explain what happened inside an application or service. They are useful for debugging specific failures, understanding request context, and reviewing edge cases after an incident.&lt;/p&gt;

&lt;p&gt;Good startup logging practices include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use structured logs, such as JSON, instead of free-form text when possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Include request IDs, user or tenant identifiers where appropriate, service name, environment, and error details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid logging secrets, tokens, payment data, or unnecessary personal data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set retention based on debugging needs and cost, not default settings.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common failure mode is logging everything. That feels safe until costs rise or engineers cannot find the few lines that matter. Start with application errors, key business workflows, background jobs, authentication events, and integration failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metrics
&lt;/h3&gt;

&lt;p&gt;Metrics show trends and current health. They are best for questions like: error rate increased, memory usage is climbing, queue depth is growing, or request latency changed after deployment.&lt;/p&gt;

&lt;p&gt;Most startups should track a small set of service-level metrics first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Request rate&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Error rate&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Latency, especially p95 or p99 where available&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CPU and memory usage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Database connection usage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Queue depth and job failure rate&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be careful with high-cardinality labels, such as user ID, request path with raw IDs, or tenant ID on every metric. They can make queries expensive and dashboards hard to use. Use detailed labels where they help diagnosis, but do not attach every possible field to every metric.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tracing
&lt;/h3&gt;

&lt;p&gt;Distributed tracing helps you follow a request across services, queues, databases, and external APIs. It becomes important when one user action touches several components and no single log line explains the delay.&lt;/p&gt;

&lt;p&gt;Tracing is especially useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A monolith is being split into services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Requests pass through an API gateway, service layer, and background workers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;External providers affect latency or reliability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Engineers cannot tell which service owns a failure.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You do not need to trace every internal detail at first. Start with entry points, service boundaries, database calls, and external API calls. Make sure trace IDs appear in logs, so engineers can move between traces and log events during debugging.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs429xfz4rtzx1ow899ci.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs429xfz4rtzx1ow899ci.webp" alt="A request path from API gateway to service layer to background workers, with tracing marked at the entry point, the service boundary, database calls and external API calls, all sharing one trace ID that also appears in log lines." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Trace the boundaries first and put the trace ID in every log line.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Alerts
&lt;/h3&gt;

&lt;p&gt;Alerts turn signals into action. Bad alerts wake people up for conditions that do not matter. Good alerts point to user impact, clear ownership, and a response path.&lt;/p&gt;

&lt;p&gt;Early alerting should focus on symptoms rather than every possible cause:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;High error rate on a user-facing service&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sustained latency above an agreed threshold&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Critical background jobs failing repeatedly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Queue backlog growing beyond normal recovery&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Database or infrastructure limits close to exhaustion&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdaxbts6jbl7ce96jpoyj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdaxbts6jbl7ce96jpoyj.webp" alt="Comparison of a cause alert, a CPU spike that may or may not affect users, against five symptom alerts: high error rate on a user-facing service, sustained latency above threshold, critical jobs failing repeatedly, queue backlog growing, and database or infra limits near exhaustion." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Page on what users feel, not on causes like a CPU spike.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If alerts are already noisy, fix that before adding more. A practical guide to &lt;a href="https://www.meteorops.com/blog/how-to-handle-alert-fatigue" rel="noopener noreferrer"&gt;handling alert fatigue&lt;/a&gt; can help you separate useful pages from low-value notifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose tools that match your stage
&lt;/h2&gt;

&lt;p&gt;The right observability tools depend on your architecture, cloud provider, team size, budget, and operational maturity. A two-person engineering team should not run a complex observability platform unless there is a strong reason. A larger team with multiple services may need stronger standards and deeper query options.&lt;/p&gt;

&lt;p&gt;Use these criteria when comparing options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setup effort:&lt;/strong&gt; How long does it take to instrument one service and get useful dashboards?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Operational burden:&lt;/strong&gt; Who patches, scales, backs up, and maintains the observability components?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data model:&lt;/strong&gt; Can the tool connect logs, metrics, and traces through shared fields like service name, environment, and request ID?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost controls:&lt;/strong&gt; Can you manage retention, sampling, indexing, and ingestion limits?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developer workflow:&lt;/strong&gt; Can engineers find what they need without learning a complex query language on day one?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration fit:&lt;/strong&gt; Does it work cleanly with your cloud, deployment pipeline, container platform, and incident process?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Managed tools are often a good fit early because they reduce maintenance work. Open source tools can be a good fit when you have the skills and time to operate them well. The main risk is choosing based on what looks powerful in a demo, then discovering the team cannot keep it clean in production.&lt;/p&gt;

&lt;p&gt;Tool choice should follow the same discipline as the rest of your platform decisions. If you need a broader framework, use the same thinking you would apply when you &lt;a href="https://www.meteorops.com/blog/how-to-choose-the-right-devops-tools-for-your-team" rel="noopener noreferrer"&gt;choose DevOps tools for your team&lt;/a&gt;: match the tool to the team’s current workload, not an imagined future state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instrument the application, not just the infrastructure
&lt;/h2&gt;

&lt;p&gt;Cloud dashboards can tell you that a container restarted, a database used more CPU, or a load balancer returned more 5xx responses. That is useful, but it rarely tells the whole story. Most startup incidents need application context.&lt;/p&gt;

&lt;p&gt;For example, a latency spike may come from a slow database query, a third-party API timeout, a feature flag path, a cache miss pattern, or a single tenant sending unusual traffic. Infrastructure metrics alone will not explain those differences.&lt;/p&gt;

&lt;p&gt;Good application instrumentation should include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Clear service names and environment names, such as production, staging, and development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Correlation IDs passed through requests, logs, and traces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consistent error handling with useful messages and stack traces where appropriate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Custom metrics for important workflows, such as signup completion, checkout failure, import job duration, or notification delivery failure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deployment markers so teams can compare behavior before and after a release.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do this incrementally. Pick one important user flow, such as login, checkout, data import, or report generation. Add logs, metrics, and traces around that path. Then repeat for the next critical flow. This produces value faster than trying to instrument every service perfectly before anyone can use the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set sensible defaults before the stack grows
&lt;/h2&gt;

&lt;p&gt;Observability gets harder to clean up later. Naming, retention, labels, and alert conventions should be simple enough for every engineer to follow.&lt;/p&gt;

&lt;p&gt;Define these defaults early:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Service naming:&lt;/strong&gt; Use consistent names across logs, metrics, traces, dashboards, and alerts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Environment naming:&lt;/strong&gt; Avoid mixing production and non-production data in the same views unless the distinction is clear.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Log levels:&lt;/strong&gt; Decide what counts as debug, info, warning, error, and critical.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Retention:&lt;/strong&gt; Keep high-value data long enough for debugging and reviews, but avoid keeping noisy data by default.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sampling:&lt;/strong&gt; Sample traces where volume is high, but keep enough detail for failed and slow requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Alert routing:&lt;/strong&gt; Send pages to people who can act. Send lower-priority notifications somewhere that does not interrupt sleep.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dashboard ownership:&lt;/strong&gt; Every dashboard should have a purpose and an owner, or it will become stale.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your startup uses Azure DevOps or is still setting up delivery foundations, observability should sit beside source control, pipelines, and release practices. The setup advice in &lt;a href="https://www.meteorops.com/blog/how-to-set-up-ado-for-startups" rel="noopener noreferrer"&gt;Azure DevOps for startups&lt;/a&gt; can help keep those foundations organized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid the common startup observability traps
&lt;/h2&gt;

&lt;p&gt;Most observability problems come from over-collecting, under-owning, or alerting on the wrong things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Too many dashboards:&lt;/strong&gt; A dashboard is useful only if someone uses it during incidents or reviews. Keep the main views focused on service health, user impact, and recent changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Logs without structure:&lt;/strong&gt; Plain text logs are harder to query and correlate. Structured logs make production debugging faster.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Metrics with uncontrolled labels:&lt;/strong&gt; High-cardinality metrics can increase cost and slow down queries. Review labels before they spread across services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Alerts tied to causes instead of symptoms:&lt;/strong&gt; CPU spikes may or may not affect users. Error rates, failed jobs, and latency usually make better primary alerts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No incident feedback loop:&lt;/strong&gt; After each incident, ask which signal was missing, which alert was noisy, and which dashboard helped. Then adjust the stack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No cost review:&lt;/strong&gt; Observability bills can grow quietly. Review ingestion, retention, and indexing on a regular schedule.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple review after each incident is often the best way to improve. If engineers spent 30 minutes looking for the right log field, add the field. If an alert fired three times with no action taken, remove it, lower its priority, or rewrite it. If a trace made the root cause obvious, expand tracing to the next important workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcgrwatoqwwo5udesfp0v.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcgrwatoqwwo5udesfp0v.webp" alt="Incident review loop: 30 minutes hunting for a log field leads to adding the field, an alert that fired 3 times with no action is removed, lowered in priority or rewritten, and a trace that made the root cause obvious leads to expanding tracing to the next workflow." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Each incident review turns one gap or noisy alert into a concrete fix.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What observability should a five-person startup set up first?
&lt;/h3&gt;

&lt;p&gt;Error tracking, structured JSON logs with a request ID, the four golden signals for each user-facing service, an uptime check on the main user flow, and a handful of alerts on user-facing symptoms (error rate, latency, failed critical jobs). Use one managed platform so nobody has to run monitoring infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should a startup self-host Prometheus and Grafana?
&lt;/h3&gt;

&lt;p&gt;Usually not at first. Self-hosting is cheaper in software but costs engineer time for upgrades, storage, scaling and on-call for the monitoring itself. It starts to pay off when your managed bill is larger than a meaningful share of a platform engineer's time, or when data residency requires it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do we need distributed tracing from day one?
&lt;/h3&gt;

&lt;p&gt;No. Tracing pays off once a request crosses several services, queues or external APIs. Start with OpenTelemetry SDKs at service entry points and outbound calls, and put trace IDs in your logs so you can jump between them.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we build one observability platform that combines alerts, logs, metrics and traces?
&lt;/h3&gt;

&lt;p&gt;Standardize on OpenTelemetry for instrumentation, send everything through an OpenTelemetry Collector, and use shared resource attributes (&lt;code&gt;service.name&lt;/code&gt;, &lt;code&gt;deployment.environment&lt;/code&gt;) so the backend can link logs, metrics and traces. Grafana Cloud and Datadog both accept OTLP, which keeps you portable.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we keep observability costs predictable?
&lt;/h3&gt;

&lt;p&gt;Set log retention and indexing rules per environment, drop debug logs in production, keep high-cardinality values (user IDs, raw URLs) out of metric labels, sample traces while keeping errors and slow requests, and review the bill monthly with the engineers who generate the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Build your startup observability stack around the questions your team needs to answer in production. Start with structured logs, essential metrics, targeted tracing, and alerts tied to real user impact. Keep the setup small enough to operate, but consistent enough to scale.&lt;/p&gt;

&lt;p&gt;The goal is not to collect every signal. The goal is to shorten the path between “something is wrong” and “we know what changed, who is affected, and what to fix next.”&lt;/p&gt;

</description>
      <category>devops</category>
      <category>sre</category>
      <category>startup</category>
      <category>performance</category>
    </item>
    <item>
      <title>Cluster Autoscaler vs Karpenter: Node Autoscaling Without Cost Surprises</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Tue, 10 Nov 2026 07:30:07 +0000</pubDate>
      <link>https://dev.to/meteorops/cluster-autoscaler-vs-karpenter-node-autoscaling-without-cost-surprises-g9m</link>
      <guid>https://dev.to/meteorops/cluster-autoscaler-vs-karpenter-node-autoscaling-without-cost-surprises-g9m</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide was written by &lt;a href="https://meteorops.com/team/michael-zion" rel="noopener noreferrer"&gt;Michael Zion&lt;/a&gt;, CEO at MeteorOps, and first published on the &lt;a href="https://meteorops.com/blog/how-to-set-up-kubernetes-autoscaling-without-creating-cost-surprises" rel="noopener noreferrer"&gt;MeteorOps blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Cluster Autoscaler adds and removes nodes in node groups you define in advance. Karpenter skips node groups and launches whichever instance type best fits the pending pods, then consolidates underused nodes. On AWS, Karpenter usually packs workloads tighter and handles Spot better. Cluster Autoscaler is the portable choice that works on every major cloud. Either way, cap total capacity explicitly.&lt;/p&gt;

&lt;p&gt;Node autoscaling is where Kubernetes cost surprises usually come from. A sensible pod autoscaler plus an unbounded node autoscaler can turn one traffic spike into a much larger bill that never scales back down. This guide compares the two node autoscalers, shows the configuration that bounds each one, and covers the workload-level guardrails that matter with either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cluster Autoscaler vs Karpenter at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Cluster Autoscaler&lt;/th&gt;
&lt;th&gt;Karpenter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;How it adds capacity&lt;/td&gt;
&lt;td&gt;Raises the desired size of an existing node group (an Auto Scaling group, managed node group or VM scale set)&lt;/td&gt;
&lt;td&gt;Creates instances directly from pending pod requirements, choosing from many instance types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instance choice&lt;/td&gt;
&lt;td&gt;Fixed per node group; you pre-create groups for each shape&lt;/td&gt;
&lt;td&gt;Any type allowed by NodePool requirements (family, size, architecture, zone, Spot or On-Demand)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale-down&lt;/td&gt;
&lt;td&gt;Removes nodes below a utilization threshold (default 50%) after they stay unneeded for a while (default 10 minutes)&lt;/td&gt;
&lt;td&gt;Consolidation deletes empty nodes and replaces underused ones with cheaper, smaller nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spot handling&lt;/td&gt;
&lt;td&gt;Mixed-instance node groups plus a separate interruption handler&lt;/td&gt;
&lt;td&gt;Built-in Spot and On-Demand selection, with interruption handling through an SQS queue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disruption controls&lt;/td&gt;
&lt;td&gt;PDBs and the &lt;code&gt;cluster-autoscaler.kubernetes.io/safe-to-evict: "false"&lt;/code&gt; annotation&lt;/td&gt;
&lt;td&gt;PDBs, NodePool disruption budgets, and the &lt;code&gt;karpenter.sh/do-not-disrupt: "true"&lt;/code&gt; annotation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost ceiling&lt;/td&gt;
&lt;td&gt;Node group max sizes and &lt;code&gt;--max-nodes-total&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;spec.limits&lt;/code&gt; on each NodePool (CPU and memory)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clouds&lt;/td&gt;
&lt;td&gt;AWS, GCP, Azure and many others&lt;/td&gt;
&lt;td&gt;AWS (v1 stable since 2024); on Azure through AKS Node Auto Provisioning, which is built on Karpenter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Main risk&lt;/td&gt;
&lt;td&gt;Many node groups to maintain; slow, coarse scaling&lt;/td&gt;
&lt;td&gt;Unbounded NodePools; churn from aggressive consolidation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg9kgztyxe5l92gubao2s.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg9kgztyxe5l92gubao2s.webp" alt="Two lanes compare node autoscalers: Cluster Autoscaler turns pending pods into a larger node group with a fixed node shape, capped by max size and --max-nodes-total; Karpenter creates best-fit instances directly, capped by NodePool spec.limits." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Both tools react to pending pods, but only the ceiling you set stops the growth.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Bound Karpenter with NodePool limits and disruption budgets
&lt;/h2&gt;

&lt;p&gt;A Karpenter NodePool without &lt;code&gt;limits&lt;/code&gt; can keep launching nodes as long as pods are pending. Always set a CPU and memory ceiling, choose the consolidation policy, and add a disruption budget so consolidation never drains too much of the cluster at once.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: general
spec:
  template:
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["c", "m", "r"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64", "arm64"]
      expireAfter: 720h          # replace nodes every 30 days
  limits:
    cpu: "200"                   # hard ceiling for this NodePool
    memory: 400Gi
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 5m
    budgets:
      - nodes: "10%"             # never disrupt more than 10% of nodes at once
      - nodes: "0"               # no voluntary disruption during business peak
        schedule: "0 9 * * mon-fri"
        duration: 8h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcujvf8ugb2dtlmgcbu62.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcujvf8ugb2dtlmgcbu62.webp" alt="Timeline of a weekday under the example NodePool budgets: up to 10% of nodes can be disrupted at once outside business hours, and 0 nodes from 09:00 to 17:00 under the schedule 0 9 * * mon-fri with duration 8h." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Consolidation keeps saving money at night but leaves the cluster alone during the business peak.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When both Spot and On-Demand are allowed, Karpenter prefers Spot and falls back to On-Demand when Spot capacity is unavailable. Allowing both architectures lets it pick cheaper Graviton instances when your images are multi-arch. Mark pods that must not be moved by consolidation (long batch jobs, singletons during a migration) with &lt;code&gt;karpenter.sh/do-not-disrupt: "true"&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bound Cluster Autoscaler with node group sizes and scale-down settings
&lt;/h2&gt;

&lt;p&gt;Cluster Autoscaler can only grow node groups up to their configured maximum, so the max size of each group is your cost ceiling. The flags below make scale-down and expansion choices explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;command:
  - ./cluster-autoscaler
  - --cloud-provider=aws
  - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/my-cluster
  - --expander=least-waste            # pick the group that wastes the least CPU and memory
  - --balance-similar-node-groups     # spread across zones evenly
  - --max-nodes-total=60              # cluster-wide ceiling
  - --scale-down-utilization-threshold=0.5
  - --scale-down-unneeded-time=10m
  - --skip-nodes-with-system-pods=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run one node group per zone for workloads with zonal volumes, and keep the number of node shapes small. If you need many instance types to chase Spot capacity, that is usually the point where Karpenter becomes simpler to operate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which one should you use?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Karpenter&lt;/strong&gt; on EKS when workloads vary in shape, you want Spot with automatic fallback, or you are paying for half-empty nodes that Cluster Autoscaler will not consolidate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Cluster Autoscaler&lt;/strong&gt; when you run on several clouds, on GKE (which has its own node auto-provisioning), when a few uniform node groups already fit your workloads, or when your team prefers predictable, fixed node shapes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;On AKS&lt;/strong&gt;, use the built-in cluster autoscaler or Node Auto Provisioning rather than installing either tool yourself.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not run both against the same nodes. When migrating from Cluster Autoscaler to Karpenter, create the NodePool, scale Cluster Autoscaler to zero replicas, then cordon and drain the old node groups gradually while PDBs protect critical workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand Which Kubernetes Layer Is Scaling
&lt;/h2&gt;

&lt;p&gt;Kubernetes autoscaling usually involves several independent control loops. They react to different signals and can amplify one another when configured carelessly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Horizontal Pod Autoscaler (HPA):&lt;/strong&gt; Changes the number of replicas for a workload, usually from CPU, memory, or a custom metric.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vertical Pod Autoscaler (VPA):&lt;/strong&gt; Recommends or changes CPU and memory requests for pods. Its operating mode needs careful review because changing requests can restart or reschedule workloads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cluster Autoscaler:&lt;/strong&gt; Adjusts the number of nodes when pods cannot be scheduled or nodes are underused, depending on its configuration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Karpenter:&lt;/strong&gt; Provisions and removes nodes based on pending pod requirements and configured constraints.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Managed node pool autoscaling:&lt;/strong&gt; Changes the size of a cloud provider’s node group according to its own minimum and maximum settings.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These layers do not share a single cost budget. An HPA can increase replicas, which creates unschedulable pods, which causes a node autoscaler to add nodes. If the HPA never scales down, or if pod requests are much larger than actual usage, the node count can remain high after traffic falls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fysucbyukij03hzi5pptt.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fysucbyukij03hzi5pptt.webp" alt="Chain diagram: a traffic spike makes the HPA add replicas, which creates unschedulable pods, which makes the node autoscaler add nodes; nodes stay after traffic falls when the HPA never scales down or requests are much larger than usage." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Each loop does its own job correctly, and the bill grows anyway.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Start by writing down the scaling path for each important workload:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;What metric increases the replica count?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the minimum and maximum replica count?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What CPU and memory requests does each replica reserve?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which node pool can run the workload?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What causes a new node to be created?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What prevents the workload from consuming unlimited capacity?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you cannot answer these questions, changing a maximum replica count is not a cost-control strategy. It is a guess.&lt;/p&gt;
&lt;h2&gt;
  
  
  Set Resource Requests Before Setting Replica Limits
&lt;/h2&gt;

&lt;p&gt;Autoscaling decisions depend on resource requests. The HPA commonly evaluates CPU utilization as a percentage of the CPU request, not as a percentage of the node's total capacity. A container with a request of 500 millicores running at 400 millicores is at 80% requested CPU, even if the node still has substantial unused capacity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwhl6swclrsfnay546ha0.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwhl6swclrsfnay546ha0.webp" alt="A container with a 500 millicore CPU request using 400 millicores is at 80% requested CPU, even though the node around it has substantial unused capacity." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Inaccurate requests skew every scaling decision the HPA makes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That makes inaccurate requests expensive in both directions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requests that are too low:&lt;/strong&gt; The scheduler packs too many pods onto a node, and the workload may experience throttling or memory pressure before the HPA reacts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requests that are too high:&lt;/strong&gt; Each replica reserves more node capacity than it needs, so scaling out creates nodes sooner and keeps them larger than necessary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Missing requests:&lt;/strong&gt; CPU-based utilization may be unsuitable or unavailable for the workload, and scheduling becomes less predictable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use measured usage from representative periods, including deployments, batch activity, and peak traffic. Do not set requests from a single quiet hour. For memory, leave enough room for normal working-set variation because memory pressure can terminate a pod before a CPU-based HPA responds.&lt;/p&gt;

&lt;p&gt;A minimal workload definition should make the resource assumptions explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: example/api:1.0.0
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "1"
              memory: "512Mi"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The image name in this example is illustrative. Replace it with the image and version used by your workload. The important part is that requests and limits reflect a tested operating range rather than arbitrary defaults.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bound the pod autoscaler too
&lt;/h2&gt;

&lt;p&gt;Node autoscalers react to pending pods, so an unbounded Horizontal Pod Autoscaler drives node cost directly. Give every HPA a deliberate &lt;code&gt;maxReplicas&lt;/code&gt;, slow scale-down (a stabilization window of about 5 minutes), and a metric that reflects real demand. A slow downstream dependency can raise CPU, add replicas, and add nodes without helping users at all. Our &lt;a href="https://meteorops.com/blog/how-to-configure-kubernetes-hpa-without-causing-scaling-flaps" rel="noopener noreferrer"&gt;Kubernetes HPA guide&lt;/a&gt; covers the configuration in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Put hard limits around namespaces and node growth
&lt;/h2&gt;

&lt;p&gt;Pod limits do not automatically create a cloud cost limit. If an HPA can create ten times as many replicas, a node autoscaler may add enough capacity to schedule them. You need limits at both the workload and cluster levels.&lt;/p&gt;

&lt;p&gt;For each node pool or provisioner, define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A minimum size that supports normal operation and planned disruption.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A maximum size that reflects the approved capacity and cost envelope.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The instance types or node sizes that the workload may use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scheduling rules that keep specialized workloads away from general-purpose capacity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A scale-down policy that removes genuinely unused nodes without disrupting critical workloads.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use a &lt;strong&gt;ResourceQuota&lt;/strong&gt; in each namespace to prevent one team or environment from consuming all available capacity. Pair it with a &lt;strong&gt;LimitRange&lt;/strong&gt; when you need default requests and limits for containers that omit them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: ResourceQuota
metadata:
  name: application-quota
  namespace: production
spec:
  hard:
    requests.cpu: "20"
    requests.memory: 40Gi
    limits.cpu: "40"
    limits.memory: 80Gi
    pods: "50"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A quota is a scheduling guardrail, not a guarantee that the cloud bill will stay below a specific amount. Node overhead, system workloads, daemon sets, storage, load balancers, and other services still consume resources. Leave capacity for those components when choosing quota values.&lt;/p&gt;

&lt;p&gt;Review node autoscaling alongside workload placement. A pod with a restrictive node selector, taint requirement, or topology rule may force the provisioner to create a new node even when another node has spare capacity. This can be the correct availability decision, but it should be visible in the cost review.&lt;/p&gt;

&lt;p&gt;Teams operating several clusters should document their node-pool limits and ownership clearly. For example, importing or consolidating clusters can expose inconsistent autoscaling rules that were previously hidden by separate cloud accounts or environments. A documented migration plan, such as the approach described in this &lt;a href="https://meteorops.com/case-studies/import-multiple-high-scale-kubernetes-clusters-into-pulumi" rel="noopener noreferrer"&gt;Kubernetes cluster import case study&lt;/a&gt;, can help keep infrastructure policy explicit during that work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Failure Modes Before Production Traffic Finds Them
&lt;/h2&gt;

&lt;p&gt;Autoscaling should be tested as a system rather than as an isolated HPA object. A useful test starts with a known workload and observes every step: metric change, replica change, pending pods, node creation, application recovery, and scale-down.&lt;/p&gt;

&lt;p&gt;Run these checks in a non-production environment or during an approved production exercise:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Increase request load until the HPA reaches several replica levels.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Confirm that new pods become ready and that readiness probes prevent traffic from reaching unready instances.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observe whether pending pods trigger node growth as expected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stop the load and measure how long replicas and nodes take to fall.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check whether scale-down causes evictions, queue loss, connection failures, or latency spikes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repeat the test while a deployment, node drain, or dependency slowdown is occurring.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Watch these signals during the test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;HPA desired replicas and current replicas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pending pods and their scheduling events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Node count, node utilization, and unschedulable nodes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CPU throttling and memory pressure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Request latency, error rate, queue depth, and saturation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replica and node count after demand returns to normal.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not judge success by node utilization alone. A cluster can look efficient while users experience high latency because the application is waiting on a database or another service. Conversely, a low-utilization node may be necessary because the workload has strict placement rules or requires spare capacity for disruption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Cost Review That Matches Scaling Behavior
&lt;/h2&gt;

&lt;p&gt;Cost control fails when engineers review the bill after the fact and cannot connect it to a scaling event. Record the decisions that can increase capacity and assign an owner to each one.&lt;/p&gt;

&lt;p&gt;At minimum, review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Changes to HPA minimum and maximum replicas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Changes to CPU and memory requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Changes to node-pool or provisioner limits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;New taints, tolerations, selectors, or topology constraints.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Changes to custom metrics and their collection intervals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Namespaces that approach their resource quotas.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use separate limits for development, staging, and production. A staging environment that inherits production replica limits can create unnecessary spend during load tests or a stuck job. Development clusters often need a firm upper bound because an accidental deployment can otherwise remain active until someone notices.&lt;/p&gt;

&lt;p&gt;When a workload needs more capacity, ask which constraint is actually failing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If requests are too high, recalibrate them from representative usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the HPA reacts to the wrong signal, change the metric rather than raising the maximum.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If pods cannot fit efficiently, review placement rules and node shapes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the workload has a legitimate sustained increase, update the capacity plan and budget deliberately.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If several clusters use different policies, standardize the policy before copying another configuration.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fikkh7pc4zb7gevdkn01k.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fikkh7pc4zb7gevdkn01k.webp" alt="Decision map for a workload that needs more capacity: requests too high, recalibrate from representative usage; HPA reacts to the wrong signal, change the metric not the maximum; pods cannot fit efficiently, review placement rules and node shapes; legitimate sustained increase, update the capacity plan and budget; clusters use different policies, standardize the policy first." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Raising a limit is the right answer only for a legitimate sustained increase.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For teams managing AWS and Kubernetes together, infrastructure changes should be reviewed as one capacity decision rather than as separate application and cloud changes. The practices in this &lt;a href="https://meteorops.com/case-studies/improve-and-simplify-aws-and-kubernetes-infrastructure-management" rel="noopener noreferrer"&gt;AWS and Kubernetes management case study&lt;/a&gt; are relevant to that type of review. Managed Kubernetes services such as &lt;a href="https://meteorops.com/technologies/azure-kubernetes-service-aks" rel="noopener noreferrer"&gt;Azure Kubernetes Service&lt;/a&gt; can reduce control-plane administration, but they do not remove the need to bound workload and node scaling.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the Configuration Needs a Larger Review
&lt;/h2&gt;

&lt;p&gt;Get a second review when autoscaling has become difficult to explain, when several teams share a cluster, or when a single traffic event can materially affect infrastructure spend. The review should examine manifests, metrics, scheduling events, quotas, node limits, and recent cost changes together.&lt;/p&gt;

&lt;p&gt;Useful deliverables include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A diagram showing the HPA, scheduler, node autoscaler, node pools, and external dependencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A table listing minimum and maximum replicas for each production workload.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A resource-request review based on observed usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A namespace quota and ownership map.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A test record showing scale-up and scale-down behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An escalation rule for reaching a capacity or spending threshold.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Infrastructure teams can also compare patterns used in production Kubernetes environments, including the operational approach described in this &lt;a href="https://meteorops.com/case-studies/scalable-biotech-cloud-infrastructure-with-apache-airflow-kubernetes-aws-and-terraform" rel="noopener noreferrer"&gt;scalable Kubernetes and cloud infrastructure case study&lt;/a&gt;. Treat those patterns as material for review, not as a substitute for testing your own workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is Karpenter better than Cluster Autoscaler?
&lt;/h3&gt;

&lt;p&gt;On AWS it is usually more cost-efficient, because it picks right-sized instances per workload, uses Spot with fallback, and consolidates underused nodes. Cluster Autoscaler is simpler to reason about, supports every major cloud, and is fine when a few uniform node groups fit your workloads.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Karpenter work on Azure or GCP?
&lt;/h3&gt;

&lt;p&gt;On Azure, yes: AKS Node Auto Provisioning is built on Karpenter and is managed for you. There is no supported Karpenter provider for GKE; use GKE's cluster autoscaler and node auto-provisioning there.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I stop Karpenter from overspending?
&lt;/h3&gt;

&lt;p&gt;Set &lt;code&gt;spec.limits&lt;/code&gt; for CPU and memory on every NodePool, restrict instance categories and sizes in &lt;code&gt;requirements&lt;/code&gt;, enable consolidation, keep accurate pod requests, and alert on node count and spend. Without limits, any burst of pending pods can launch new nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is my Cluster Autoscaler not scaling down?
&lt;/h3&gt;

&lt;p&gt;Common causes: pods with local storage or the &lt;code&gt;safe-to-evict: "false"&lt;/code&gt; annotation, PDBs that allow 0 disruptions, kube-system pods without PDBs, nodes above the utilization threshold, or pods that cannot fit on any other node because of affinity, taints or zonal volumes. Check the autoscaler logs and the &lt;code&gt;cluster-autoscaler-status&lt;/code&gt; ConfigMap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I run Karpenter and Cluster Autoscaler together?
&lt;/h3&gt;

&lt;p&gt;Only on separate sets of nodes, and only temporarily during a migration. If both manage the same capacity they make conflicting decisions. Scale Cluster Autoscaler to zero once Karpenter NodePools are serving the workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Pick the node autoscaler that fits your cloud and workload mix, then set autoscaling limits in layers. Give workloads accurate resource requests, bound HPA replicas, cap node-pool growth, use namespace quotas, and test the complete path from demand to cloud capacity. Then review scaling changes as capacity decisions with clear ownership. This approach keeps autoscaling useful during real demand without allowing an HPA or node provisioner to define your cloud bill by accident.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>aws</category>
      <category>devops</category>
      <category>sre</category>
    </item>
    <item>
      <title>Liveness vs Readiness Probe: Kubernetes Config That Avoids Restart Loops</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Mon, 09 Nov 2026 07:30:11 +0000</pubDate>
      <link>https://dev.to/meteorops/liveness-vs-readiness-probe-kubernetes-config-that-avoids-restart-loops-4dn1</link>
      <guid>https://dev.to/meteorops/liveness-vs-readiness-probe-kubernetes-config-that-avoids-restart-loops-4dn1</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide was written by &lt;a href="https://meteorops.com/team/michael-zion" rel="noopener noreferrer"&gt;Michael Zion&lt;/a&gt;, CEO at MeteorOps, and first published on the &lt;a href="https://meteorops.com/blog/how-to-configure-kubernetes-liveness-probes-without-causing-restart-loops" rel="noopener noreferrer"&gt;MeteorOps blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;A Kubernetes liveness probe tells the kubelet when to restart a container; a readiness probe only removes the pod from Service traffic and never restarts it. To avoid restart loops, keep liveness checks local to the process, move dependency checks to readiness, use a startupProbe for slow boots, and set timeouts of 2 to 3 seconds.&lt;/p&gt;

&lt;p&gt;The goal is not to make liveness probes pass more often. It is to use them only for conditions a restart can actually fix, and to give the application enough time to prove it is truly wedged before Kubernetes kills it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Liveness vs readiness vs startup probes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Probe&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;What happens on failure&lt;/th&gt;
&lt;th&gt;What it should check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;livenessProbe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Is the process wedged beyond recovery?&lt;/td&gt;
&lt;td&gt;The kubelet kills and restarts the container (per &lt;code&gt;restartPolicy&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;Local process health only: event loop responsive, no fatal internal state.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;readinessProbe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Can this pod take traffic right now?&lt;/td&gt;
&lt;td&gt;The pod is removed from Service endpoints. No restart.&lt;/td&gt;
&lt;td&gt;Dependencies, warm caches, draining state.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;startupProbe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Has the app finished booting?&lt;/td&gt;
&lt;td&gt;Liveness and readiness are held back until it passes. If it never passes within &lt;code&gt;failureThreshold x periodSeconds&lt;/code&gt;, the container is restarted.&lt;/td&gt;
&lt;td&gt;Initialization complete: migrations, cache load, model load.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcgb774wcke5xzzg5wkr6.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcgb774wcke5xzzg5wkr6.webp" alt="Diagram of what each Kubernetes probe does on failure: a failing livenessProbe makes the kubelet restart the container, a failing readinessProbe removes the pod from Service endpoints with no restart, and a startupProbe holds back liveness and readiness and restarts the container if it never passes." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Only liveness and startup failures restart the container; readiness only controls traffic.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Understand what a liveness probe is allowed to do
&lt;/h2&gt;

&lt;p&gt;A liveness probe answers one narrow question: “Should Kubernetes restart this container?” If the probe fails enough times, the kubelet restarts the container according to the pod’s restart policy. That is powerful, but it is also blunt.&lt;/p&gt;

&lt;p&gt;A liveness probe should detect problems such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A process deadlock where the application stops serving all useful work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A stuck event loop that no longer responds locally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A broken internal state that only a process restart can clear.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A worker process that is alive at the operating system level but cannot make progress.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A liveness probe should usually avoid checking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Database reachability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Message broker availability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Third-party API status.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Availability of another internal service.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Long-running migrations or warm-up tasks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the database is unavailable and every pod fails its liveness probe because of that database check, Kubernetes will restart every pod. The restart will not fix the database. It will add load, increase cold starts, clear in-memory caches, and make recovery harder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5gm7rc45g0qmbp0u42cx.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5gm7rc45g0qmbp0u42cx.webp" alt="Side by side comparison of a database outage: with the database check in liveness, every pod fails liveness and Kubernetes restarts every pod, adding load, more cold starts and clearing in-memory caches without fixing the database; with the check in readiness, pods are removed from Service endpoints with no restart and caches stay warm." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Put dependency checks in readiness so an outage removes pods from traffic instead of restarting them all.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Use the right probe for the right job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;startupProbe&lt;/strong&gt;: gives slow-starting containers time to initialize before liveness checks begin.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;readinessProbe&lt;/strong&gt;: controls whether the pod receives traffic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;livenessProbe&lt;/strong&gt;: restarts the container when it is truly unhealthy.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you manage Kubernetes manifests through infrastructure as code, keep this distinction explicit in your modules or templates. The same principle applies whether you apply raw YAML, use Helm, or &lt;a href="https://www.meteorops.com/blog/deploy-kubernetes-resources-using-terraform" rel="noopener noreferrer"&gt;deploy Kubernetes resources using Terraform&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Start with a safe baseline configuration
&lt;/h2&gt;

&lt;p&gt;Begin with conservative thresholds, then tighten them after observing real startup time and failure behavior. Do not copy probe values across services without checking how each service starts, warms up, and handles load.&lt;/p&gt;

&lt;p&gt;Here is a risky liveness probe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: example/api:1.0.0
          ports:
            - containerPort: 8080
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
            timeoutSeconds: 1
            failureThreshold: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can restart the container after roughly 20 seconds: 5 seconds of initial delay, then 3 failed probes spaced 5 seconds apart. If the service sometimes needs 45 seconds to load configuration, run migrations, compile templates, or warm caches, this pod can restart forever.&lt;/p&gt;

&lt;p&gt;A safer pattern separates startup, readiness, and liveness:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: example/api:1.0.0
          ports:
            - name: http
              containerPort: 8080

          startupProbe:
            httpGet:
              path: /startupz
              port: http
            periodSeconds: 5
            timeoutSeconds: 2
            failureThreshold: 24

          readinessProbe:
            httpGet:
              path: /readyz
              port: http
            periodSeconds: 5
            timeoutSeconds: 2
            failureThreshold: 3
            successThreshold: 1

          livenessProbe:
            httpGet:
              path: /livez
              port: http
            periodSeconds: 10
            timeoutSeconds: 2
            failureThreshold: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the startup probe allows up to about 120 seconds for startup: 24 failures multiplied by a 5-second period. While the startup probe is still failing, Kubernetes does not run the liveness probe. After startup succeeds, liveness begins.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjv4v5gqkt90pqf3jwd8x.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjv4v5gqkt90pqf3jwd8x.webp" alt="Timeline comparing the risky liveness probe, which restarts the container at 20 seconds (5 second delay plus 3 failures of 5 seconds) and restarts forever because the app is only ready at 45 seconds, with a startupProbe whose 24 x 5 second window allows 120 seconds, so startup passes at 45 seconds and liveness begins after it." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A startupProbe window longer than slow startup lets the app finish booting before liveness can restart it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This matters for applications with variable boot times, such as Java services, applications that load large models, services that hydrate caches, or workers that recover state during startup.&lt;/p&gt;
&lt;h2&gt;
  
  
  Use practical threshold math before shipping
&lt;/h2&gt;

&lt;p&gt;You should be able to explain every probe value in a deployment review. If the answer is “we copied it,” the probe is not tuned.&lt;/p&gt;

&lt;p&gt;Use this rough calculation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;restart window ≈ initialDelaySeconds + (failureThreshold × periodSeconds)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a liveness probe like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;livenessProbe:
  httpGet:
    path: /livez
    port: http
  initialDelaySeconds: 30
  periodSeconds: 10
  timeoutSeconds: 2
  failureThreshold: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes may restart the container after about 60 seconds of failing liveness checks. That may be fine for a stateless API with a 10-second normal startup time. It may be too aggressive for a batch worker that can pause during garbage collection, checkpoint recovery, or CPU pressure.&lt;/p&gt;

&lt;p&gt;Use these starting points as a practical baseline, then adjust with real data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;startupProbe&lt;/strong&gt;: set &lt;code&gt;failureThreshold × periodSeconds&lt;/code&gt; higher than your slow but acceptable startup time. If p95 startup is 70 seconds, start around 120 seconds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;readinessProbe&lt;/strong&gt;: keep it responsive. A period of 5 to 10 seconds is common because it controls traffic routing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;livenessProbe&lt;/strong&gt;: keep it less aggressive than readiness. A period of 10 to 30 seconds with a failure threshold of 3 is a safer default for many services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;timeoutSeconds&lt;/strong&gt;: avoid the default of 1 second for applications that can pause briefly under load. Start with 2 or 3 seconds if you have no better data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;initialDelaySeconds&lt;/strong&gt;: prefer &lt;code&gt;startupProbe&lt;/code&gt; for startup handling. Use &lt;code&gt;initialDelaySeconds&lt;/code&gt; only when startup behavior is simple and predictable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Probe tuning should live next to deployment configuration, not in someone’s notes. If your platform team provisions services and dependencies through Kubernetes-native control planes, document probe defaults in the same place you manage patterns such as &lt;a href="https://www.meteorops.com/blog/deploy-aws-resources-using-crossplane-on-kubernetes" rel="noopener noreferrer"&gt;deploying AWS resources using Crossplane on Kubernetes&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design health endpoints that match probe intent
&lt;/h2&gt;

&lt;p&gt;The endpoint behind the probe matters more than the YAML. A clean probe configuration still fails if &lt;code&gt;/health&lt;/code&gt; does too much work.&lt;/p&gt;

&lt;p&gt;A good pattern is to expose separate endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/livez&lt;/code&gt;: checks that the process can respond and has not entered a fatal internal state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/readyz&lt;/code&gt;: checks whether the application can serve traffic right now.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/startupz&lt;/code&gt;: checks whether initialization has completed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, an HTTP service might implement behavior like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /livez
200 OK if the process event loop is responsive
500 only if the process is internally unrecoverable

GET /readyz
200 OK if the service can accept traffic
503 if required dependencies are unavailable or the app is draining

GET /startupz
200 OK after bootstrapping is complete
503 while migrations, cache loading, or state recovery are still running
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a minimal Node.js example that keeps liveness local and pushes dependency checks into readiness:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express from "express";

const app = express();

let started = false;
let shuttingDown = false;

async function checkDatabase() {
  // Replace with a cheap ping or connection-pool status check.
  // Do not run expensive queries here.
  return true;
}

app.get("/startupz", (req, res) =&amp;gt; {
  if (started) {
    return res.status(200).send("ok");
  }

  return res.status(503).send("starting");
});

app.get("/livez", (req, res) =&amp;gt; {
  // Keep this local. Do not check the database, cache, or third-party APIs.
  return res.status(200).send("ok");
});

app.get("/readyz", async (req, res) =&amp;gt; {
  if (shuttingDown || !started) {
    return res.status(503).send("not ready");
  }

  const databaseOk = await checkDatabase();

  if (!databaseOk) {
    return res.status(503).send("database unavailable");
  }

  return res.status(200).send("ok");
});

process.on("SIGTERM", () =&amp;gt; {
  shuttingDown = true;
  setTimeout(() =&amp;gt; process.exit(0), 10_000);
});

app.listen(8080, async () =&amp;gt; {
  // Run startup work here.
  started = true;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For worker services without HTTP servers, an &lt;code&gt;exec&lt;/code&gt; probe can work, but use it carefully. Every probe spawns a process inside the container. At scale, expensive exec probes can add measurable overhead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;livenessProbe:
  exec:
    command:
      - /bin/sh
      - -c
      - test -f /tmp/worker-alive
  periodSeconds: 15
  timeoutSeconds: 2
  failureThreshold: 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use an exec probe, keep the command fast and deterministic. Avoid commands that call external systems, perform file tree scans, invoke package managers, or depend on shells that may not exist in minimal images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roll out probe changes with evidence
&lt;/h2&gt;

&lt;p&gt;Treat probe changes like production behavior changes. They can cause restarts, remove pods from service, and change rollout timing.&lt;/p&gt;

&lt;p&gt;Use this rollout process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Measure current startup time.&lt;/strong&gt; Check container logs, application metrics, and Kubernetes events. Record typical and slow startup durations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add or tune &lt;code&gt;startupProbe&lt;/code&gt;.&lt;/strong&gt; Make sure the allowed startup window exceeds slow but valid startup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Split liveness and readiness endpoints.&lt;/strong&gt; Keep restart logic separate from traffic-routing logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deploy to a small scope first.&lt;/strong&gt; Use one environment, one namespace, or one replica set before changing every workload.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Watch events during rollout.&lt;/strong&gt; Confirm that restarts are not increasing unexpectedly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Load test or replay traffic if possible.&lt;/strong&gt; Validate that probes still pass during CPU pressure, garbage collection pauses, and dependency latency.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Useful commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get pods -n app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl describe pod -n app api-7c9f6d8f7f-x2abc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl logs -n app api-7c9f6d8f7f-x2abc --previous
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get events -n app --sort-by=.lastTimestamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for messages like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Liveness probe failed: HTTP probe failed with statuscode: 503
Back-off restarting failed container
Readiness probe failed: Get "http://10.0.1.25:8080/readyz": context deadline exceeded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;--previous&lt;/code&gt; logs show that the application was still starting when it was killed, your startup window is too short or your liveness probe is starting too early. If logs show request latency spikes before liveness failures, your timeout may be too low or the endpoint may share overloaded application threads.&lt;/p&gt;

&lt;p&gt;When Kubernetes is part of a larger platform rollout, probe settings should be reviewed with resource requests, limits, rollout strategy, and dependency provisioning. For example, an application deployed on Amazon Elastic Kubernetes Service (EKS) can still fail because a probe ignores slow boot behavior, even if the cluster itself is healthy. The same operational checks apply when you &lt;a href="https://www.meteorops.com/blog/deploy-apache-airflow-on-aws-elastic-kubernetes-service-eks" rel="noopener noreferrer"&gt;deploy Apache Airflow on AWS EKS&lt;/a&gt; or run a custom API service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid the common liveness probe traps
&lt;/h2&gt;

&lt;p&gt;Most restart loops come from a few repeatable mistakes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trap 1: Dependency checks in liveness
&lt;/h3&gt;

&lt;p&gt;If &lt;code&gt;/livez&lt;/code&gt; fails when PostgreSQL, Redis, Kafka, or an external API is unavailable, you are asking Kubernetes to restart your application because another system has a problem.&lt;/p&gt;

&lt;p&gt;Move dependency checks to readiness:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;readinessProbe:
  httpGet:
    path: /readyz
    port: http
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 3

livenessProbe:
  httpGet:
    path: /livez
    port: http
  periodSeconds: 15
  timeoutSeconds: 2
  failureThreshold: 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Trap 2: No startup probe for slow applications
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;initialDelaySeconds&lt;/code&gt; can work for simple services, but it is a fixed delay. It does not adapt to real startup progress. A &lt;code&gt;startupProbe&lt;/code&gt; lets Kubernetes wait until startup succeeds, then begins liveness checks.&lt;/p&gt;

&lt;p&gt;Use startup probes for services with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Large dependency injection graphs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Database migrations or schema checks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cache warm-up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Model loading.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;State recovery after shutdown.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Trap 3: Timeout too low under CPU pressure
&lt;/h3&gt;

&lt;p&gt;The default &lt;code&gt;timeoutSeconds&lt;/code&gt; is 1 second. That can be too low for applications under CPU throttling, garbage collection, or temporary I/O pressure.&lt;/p&gt;

&lt;p&gt;If probes fail during load but the application recovers without a restart, increase &lt;code&gt;timeoutSeconds&lt;/code&gt;, increase &lt;code&gt;failureThreshold&lt;/code&gt;, or make the probe endpoint cheaper. Also check CPU limits. A pod with a tight CPU limit can fail probes because the process cannot get scheduled quickly enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trap 4: Redirects, auth, or middleware on health routes
&lt;/h3&gt;

&lt;p&gt;Health endpoints should avoid authentication middleware, redirects, rate limits, and expensive request logging. The kubelet counts any status from 200 to 399 as success, so &lt;code&gt;401&lt;/code&gt;, &lt;code&gt;403&lt;/code&gt; and &lt;code&gt;5xx&lt;/code&gt; responses fail the probe. Redirects to the same host are followed; a redirect to a different host is treated as success with a warning event, which can hide a broken endpoint.&lt;/p&gt;

&lt;p&gt;Make health routes boring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Return directly from the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do not require tokens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do not redirect HTTP to HTTPS inside the pod unless the probe is configured for HTTPS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do not call external services from liveness.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Trap 5: Probe port does not match the container
&lt;/h3&gt;

&lt;p&gt;Named ports reduce mistakes when container ports change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ports:
  - name: http
    containerPort: 8080

livenessProbe:
  httpGet:
    path: /livez
    port: http
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use service meshes or sidecars, confirm whether the kubelet probes the application container directly or whether probe rewriting is active. Misconfigured sidecar behavior can make a healthy application look unhealthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix the common probe error messages
&lt;/h2&gt;

&lt;p&gt;These are the exact strings you will see in &lt;code&gt;kubectl describe pod&lt;/code&gt; and &lt;code&gt;kubectl get events&lt;/code&gt;, with what they usually mean.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcn4avo0evotfaljkb4bs.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcn4avo0evotfaljkb4bs.webp" alt="Table style diagram mapping probe event messages to fixes: statuscode 500 means make liveness local and move checks to readiness, context deadline exceeded means raise timeoutSeconds to 2 or 3, connection refused means add a startupProbe and check the port, Back-off restarting failed container means find whether it is a probe failure or a process exit, and a readiness failure with no restart is expected so fix the dependency." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Each common probe error points to a different fix, so read the event message before changing thresholds.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Liveness probe failed: HTTP probe failed with statuscode: 500
&lt;/h3&gt;

&lt;p&gt;The endpoint answered, but with an error. Usually &lt;code&gt;/livez&lt;/code&gt; runs dependency checks (database, cache, another service) that are down. Make liveness local and move those checks to readiness. If the app really returns 500 because it is broken, check &lt;code&gt;kubectl logs POD --previous&lt;/code&gt; for the cause of the crash before tuning anything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Liveness probe failed: Get "&lt;a href="http://10.0.1.25:8080/livez%22:" rel="noopener noreferrer"&gt;http://10.0.1.25:8080/livez":&lt;/a&gt; context deadline exceeded (Client.Timeout exceeded while awaiting headers)
&lt;/h3&gt;

&lt;p&gt;The endpoint did not answer within &lt;code&gt;timeoutSeconds&lt;/code&gt; (default 1 second). Common causes are CPU throttling from a tight CPU limit, garbage collection pauses, or the health route sharing a saturated thread pool. Raise &lt;code&gt;timeoutSeconds&lt;/code&gt; to 2 or 3, raise &lt;code&gt;failureThreshold&lt;/code&gt;, and check CPU throttling metrics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Liveness probe failed: dial tcp 10.0.1.25:8080: connect: connection refused
&lt;/h3&gt;

&lt;p&gt;Nothing is listening yet, or the probe points at the wrong port. During startup this means the liveness probe started too early: add a startupProbe. Otherwise, check that the probe port matches the container port, ideally by using a named port.&lt;/p&gt;

&lt;h3&gt;
  
  
  Back-off restarting failed container
&lt;/h3&gt;

&lt;p&gt;The container restarted several times and the kubelet is now waiting with an exponential back-off (up to 5 minutes) before the next attempt. The pod shows &lt;code&gt;CrashLoopBackOff&lt;/code&gt;. Find whether the restarts come from probe failures (events say "Container api failed liveness probe, will be restarted") or from the process exiting on its own (exit code in &lt;code&gt;kubectl describe pod&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Readiness probe failed but the container is not restarting
&lt;/h3&gt;

&lt;p&gt;That is expected. Readiness failures only remove the pod from Service endpoints. If the pod never becomes ready, fix the dependency or the readiness logic; restarts will not help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use this final checklist before merging
&lt;/h2&gt;

&lt;p&gt;Before you merge a liveness probe change, verify these points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/livez&lt;/code&gt; checks only local process health.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/readyz&lt;/code&gt; handles dependency checks and traffic eligibility.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/startupz&lt;/code&gt; exists for slow or variable startup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The startup window is longer than slow but valid startup time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The liveness restart window is long enough to survive short pauses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;timeoutSeconds&lt;/code&gt; is realistic for your runtime and CPU limits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Health endpoints bypass auth, redirects, and expensive middleware.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Probe failures are visible in logs, metrics, or Kubernetes events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The rollout plan limits blast radius.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does a readiness probe failure restart the container?
&lt;/h3&gt;

&lt;p&gt;No. Only liveness and startup probe failures restart a container. A failing readiness probe removes the pod from Service endpoints until it passes again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does a startup probe failure restart the container?
&lt;/h3&gt;

&lt;p&gt;Yes. If the startup probe keeps failing past &lt;code&gt;failureThreshold x periodSeconds&lt;/code&gt;, the kubelet kills the container and restarts it, just like a liveness failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are good default liveness probe values?
&lt;/h3&gt;

&lt;p&gt;A practical starting point is &lt;code&gt;periodSeconds: 10&lt;/code&gt;, &lt;code&gt;timeoutSeconds: 2&lt;/code&gt; and &lt;code&gt;failureThreshold: 3&lt;/code&gt;, with a startupProbe covering your slowest normal boot. Tune from observed startup time and pause behavior, not copied defaults. The official reference is the Kubernetes guide to &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/" rel="noopener noreferrer"&gt;configuring liveness, readiness and startup probes&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should a liveness probe check the database?
&lt;/h3&gt;

&lt;p&gt;No. If the database goes down, every pod fails liveness and restarts at once, which adds load and slows recovery without fixing anything. Check dependencies in readiness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use the same endpoint for liveness and readiness?
&lt;/h3&gt;

&lt;p&gt;You can, but it is a common source of restart loops. Separate &lt;code&gt;/livez&lt;/code&gt; and &lt;code&gt;/readyz&lt;/code&gt; endpoints let readiness react to dependencies while liveness stays local.&lt;/p&gt;

&lt;p&gt;Liveness probes are useful when they restart containers that cannot recover on their own. They become dangerous when they replace readiness checks, dependency monitoring, or startup handling. Start conservative, separate probe responsibilities, watch real failure events, and tune based on observed behavior rather than copied defaults.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>sre</category>
      <category>performance</category>
    </item>
    <item>
      <title>How to Build a DevOps Team</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Sun, 08 Nov 2026 07:30:09 +0000</pubDate>
      <link>https://dev.to/meteorops/how-to-build-a-devops-team-3koc</link>
      <guid>https://dev.to/meteorops/how-to-build-a-devops-team-3koc</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide was written by &lt;a href="https://meteorops.com/team/michael-zion" rel="noopener noreferrer"&gt;Michael Zion&lt;/a&gt;, CEO at MeteorOps, and first published on the &lt;a href="https://meteorops.com/blog/how-to-build-a-devops-team" rel="noopener noreferrer"&gt;MeteorOps blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're considering how to build a &lt;a href="https://meteorops.com/glossary/devops" rel="noopener noreferrer"&gt;DevOps&lt;/a&gt; team the best way possible, this one's for you.&lt;/p&gt;

&lt;p&gt;This post sums up the advice I give people building DevOps teams: CTOs, VPs of R&amp;amp;D, Team Leaders, and more.&lt;/p&gt;

&lt;p&gt;You'll get a step-by-step path from philosophy and mission to roadmap, team shape by stage, sizing, and hiring (or bringing in outside help), plus a short FAQ.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I'll give you the bottom line.&lt;br&gt;&lt;br&gt;
These are the steps for building your DevOps team:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Polish your DevOps Philosophy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understand the DevOps Lead responsibilities: Product, Project, People, Service, Architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Define your Team's Mission Statement&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set useful DevOps Goals &amp;amp; Practices&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set Guiding DevOps Principles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Define the DevOps team's roadmap &amp;amp; strategy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set a definition of done&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Common DevOps teams pitfalls&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pick a team shape that fits your stage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://meteorops.com/blog/calculating-your-companys-required-devops-capacity" rel="noopener noreferrer"&gt;Calculate your team's required capacity&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hire the right DevOps Engineers&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also apply these to existing DevOps teams and level-up your organization.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Polish your DevOps Philosophy
&lt;/h2&gt;

&lt;p&gt;You must first understand why organizations need DevOps, and how it can work in practice.&lt;/p&gt;

&lt;p&gt;DevOps is an enabler role.&lt;/p&gt;

&lt;p&gt;It's meant to &lt;strong&gt;enable the developers to build, improve, and take ownership over the system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's break it down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build&lt;/strong&gt; = Create something new. Could be a new microservice, a new database, or a new monitoring dashboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improve&lt;/strong&gt; = Introduce a change into something that exists. Could be fixing a bug, changing a database schema, or changing an alert threshold.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Take ownership&lt;/strong&gt; = Take charge of problems that arise with what you built and improved. This means when something needs improvement, the owner is the one who does it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above are what the developers should do.&lt;/p&gt;

&lt;p&gt;Ownership includes on-call: the team that builds a service should be the one paged for it. DevOps owns the platform underneath it, plus the tooling that keeps on-call manageable (actionable alerts, dashboards, runbooks).&lt;/p&gt;

&lt;p&gt;Now, &lt;strong&gt;DevOps should enable it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Note: enabling &lt;strong&gt;is not&lt;/strong&gt; giving full permissions and letting them have fun.&lt;/p&gt;

&lt;p&gt;To enable is to give developers what they need to build, improve, and own the system.&lt;/p&gt;

&lt;p&gt;But do it safely, and in a way that points the developers' energy in the right direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand the DevOps Lead Responsibilities
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.prod.website-files.com%2F6203daf47137054c031fa0e6%2F670d21d66de0b9f5f31ca0fe_670d21204458519e4d043177_670d20c383c0544db1d1fa4f_66f349e5c63c8ddc4ade3d36_66f3489c3ccbcf8e80763509_Untitled_Artwork%252525202.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.prod.website-files.com%2F6203daf47137054c031fa0e6%2F670d21d66de0b9f5f31ca0fe_670d21204458519e4d043177_670d20c383c0544db1d1fa4f_66f349e5c63c8ddc4ade3d36_66f3489c3ccbcf8e80763509_Untitled_Artwork%252525202.avif" alt="The five hats of a DevOps lead" width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have 5 hats as a DevOps Lead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Product (Platform)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Your clients are your company's developers.&lt;br&gt;&lt;br&gt;
Provide them with tools, knowledge, and automations.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Tools&lt;/strong&gt; = Polished automations.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Automations&lt;/strong&gt; = Automated knowledge.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Knowledge&lt;/strong&gt; = Hard-earned information &amp;amp; insights.&lt;br&gt;&lt;br&gt;
Understand their requirements, and use Tools, Automations, and Knowledge to fulfill them.&lt;br&gt;&lt;br&gt;
Understand why they want what they want: Is it because of an underlying issue with the system? If yes, solve it before building anything.&lt;br&gt;&lt;br&gt;
If a tool or automation will save time, consider building or implementing it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Don't let your developers wait until you do something "the right way".&lt;br&gt;&lt;br&gt;
Sometimes they need immediate help to complete something.&lt;br&gt;&lt;br&gt;
Help them first, and invest time later in automation and tooling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Project&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Managing your DevOps team requires managing the work it does.&lt;br&gt;&lt;br&gt;
Turn the team's philosophy into a mission.&lt;br&gt;&lt;br&gt;
Turn the team's mission into goals.&lt;br&gt;&lt;br&gt;
Turn the team's goals into a roadmap.&lt;br&gt;&lt;br&gt;
Turn the team's roadmap into tasks.&lt;br&gt;&lt;br&gt;
Prioritize the tasks.&lt;br&gt;&lt;br&gt;
Set simple roles and responsibilities.&lt;br&gt;&lt;br&gt;
Hold your team members accountable to progression.&lt;br&gt;&lt;br&gt;
Make it easy to inform relevant team members on updates.&lt;br&gt;&lt;br&gt;
Make it easy to consult with a teammate on a subject of their expertise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;People&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Each DevOps team member enjoys some types of work more than others.&lt;br&gt;&lt;br&gt;
One enjoys sharing knowledge, another enjoys being of service, and some enjoy building tools.&lt;br&gt;&lt;br&gt;
Different teammates are also interested in different subjects: Monitoring, Infrastructure, CI/CD, etc.&lt;br&gt;&lt;br&gt;
A team member that's working on what they enjoy is more fulfilled and productive.&lt;br&gt;&lt;br&gt;
Strive to overlap each teammate's goals with the company's goals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You have 2 architectures to worry about.&lt;br&gt;&lt;br&gt;
1) The company's product architecture (built by the developers).&lt;br&gt;&lt;br&gt;
2) The DevOps platform's architecture (built by the DevOps team).&lt;br&gt;&lt;br&gt;
Help the developers understand and control the application's effect on the infrastructure.&lt;br&gt;&lt;br&gt;
Enable the developers to make informed decisions by providing context.&lt;br&gt;&lt;br&gt;
Finally, build the platform to support the developers requirements.&lt;br&gt;&lt;br&gt;
At every step, only limit decisions that damage the company.&lt;br&gt;&lt;br&gt;
Examples: High cost, Stability impairment, Restricts observability, etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Define Your DevOps Team's Mission Statement
&lt;/h2&gt;

&lt;p&gt;Here's one for you:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Enable the developers to build, improve, and own the system".&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's pretty minimal, so it's going to help your team stay focused.&lt;/p&gt;

&lt;p&gt;A healthy sign it catches on: When the team debates a decision regarding a task, they ask &lt;em&gt;"Does it help us enable the developers to build, improve, or own the system?"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That's when you win.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Useful DevOps Goals &amp;amp; Practices
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.prod.website-files.com%2F6203daf47137054c031fa0e6%2F670d21d66de0b9f5f31ca104_670d216c79c1cdd579ae0b85_Set%252520useful%252520DevOps%252520Goals%252520%252526%2525C2%2525A0Practices.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.prod.website-files.com%2F6203daf47137054c031fa0e6%2F670d21d66de0b9f5f31ca104_670d216c79c1cdd579ae0b85_Set%252520useful%252520DevOps%252520Goals%252520%252526%2525C2%2525A0Practices.avif" alt="Set useful DevOps goals and practices" width="799" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your company's success will be determined by its speed and its product's quality.&lt;br&gt;&lt;br&gt;
To make it happen, remember that programming is science, not maths. I'll explain.&lt;/p&gt;

&lt;p&gt;People used to think programming would be a mathematical discipline.&lt;br&gt;&lt;br&gt;
They thought programmers would write functions and prove them mathematically.&lt;/p&gt;

&lt;p&gt;That's not what happened. Programming is a &lt;strong&gt;scientific&lt;/strong&gt; discipline.&lt;br&gt;&lt;br&gt;
You write code, you test it, and you assume it's good until a test fails.&lt;/p&gt;

&lt;p&gt;In essence, you're experimenting.&lt;/p&gt;

&lt;p&gt;You might ask: &lt;em&gt;"wtf? how's this related to setting useful goals?"&lt;/em&gt;&lt;br&gt;&lt;br&gt;
The answer is that the first thing you want to enable is running experiments easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  So here are some useful goals:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Developers can easily test their code in a consistent manner&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Production and testing environments are identical (Production will benefit from the quality of the tests)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developers can easily collaborate&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developers can understand the state of the system and the impact of changes&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's translate those goals into smaller goals or practices that will achieve the goals:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Developers can &lt;a href="https://meteorops.com/blog/one-click-environment-the-ultimate-devops-goal" rel="noopener noreferrer"&gt;create a testing/production environment with "One-Click"&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A continuous integration process lets developers collaborate by agreeing on the current, up-to-date version of the system&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Auto-create dashboards and alerts for new services&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Set Guiding DevOps Principles
&lt;/h2&gt;

&lt;p&gt;Some useful DevOps principles that help save your team time, improve the speed of delivery, and keep the system healthy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PoC before doing things "the right way"&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Make it work, then make it better&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The entire system should be fully recoverable from Git&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use tools with a big community and well-documented interface&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Equip key-developers with DevOps knowledge to be the first point-of-contact for their team members (super users)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For more principles with examples, see &lt;a href="https://meteorops.com/blog/the-cto-devops-handbook-simple-principles-and-examples" rel="noopener noreferrer"&gt;The CTO DevOps Handbook&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the DevOps Team's Roadmap &amp;amp; Strategy
&lt;/h2&gt;

&lt;p&gt;Roadmap = Goals * Strategy.&lt;/p&gt;

&lt;p&gt;Once you set the goals (as mentioned above), you can start prioritizing.&lt;/p&gt;

&lt;h3&gt;
  
  
  #1 - The DevOps Categories
&lt;/h3&gt;

&lt;p&gt;Enabling developers requires a DevOps Engineer to handle and enable the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Provision infrastructure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deploy workloads&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Monitor the system&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Recover from issues&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scale up and down&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Track &amp;amp; test changes (Codebase Management)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Secure the system&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Store &amp;amp; retrieve data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure the system&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  #2 - Examine each goal through each category
&lt;/h3&gt;

&lt;p&gt;Every DevOps goal you set should be examined through the lens of each category.&lt;/p&gt;

&lt;p&gt;Together, the categories cover every aspect of building, improving, and owning a software operation.&lt;/p&gt;

&lt;p&gt;Let's do an example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Goal: Create a "One-Click Environment Automation"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Categories to address:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How should its infrastructure be provisioned?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How should its workloads be deployed?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How should its metrics and logs be sent, stored, and queried?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;...&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  #3 - Strategic Principles
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Spend at least 50% of the team's capacity on DevOps goals as soon as you responsibly can:&lt;br&gt;&lt;br&gt;
Support the developers and teach them how to self-support to get there&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy to modify &amp;gt; Perfect:&lt;br&gt;&lt;br&gt;
When time forces you to do something imperfectly, do it in a way that's easy to improve later&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prerequisites first:&lt;br&gt;&lt;br&gt;
Codebase Management -&amp;gt; Infrastructure -&amp;gt; Deployment -&amp;gt; Configuration -&amp;gt; Data Management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At least moderate foundations quickly, reinforce later, but never weak foundations:&lt;br&gt;&lt;br&gt;
If something is a foundation (like infrastructure) and early on you lack boilerplates or experience with it, don't settle for weak foundations. But don't over-invest in strong ones if that takes too long, either.&lt;br&gt;&lt;br&gt;
Instead, moderately invest in the foundation, and revisit it later.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Set a Definition of Done
&lt;/h2&gt;

&lt;p&gt;Think of it as the checklist a component must pass before you call it production-ready.&lt;/p&gt;

&lt;p&gt;Ask the following questions for every single component in your system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Monitoring&lt;/em&gt;&lt;/strong&gt;: Are there metrics, logs, traces, and alerts setup in an actionable way?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Availability&lt;/em&gt;&lt;/strong&gt;: Is there a mechanism to keep it alive during incidents?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Resiliency&lt;/em&gt;&lt;/strong&gt;: Can it recover from an error quickly?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Recovery&lt;/em&gt;&lt;/strong&gt;: Can it be fully restored to a previous state?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Testability&lt;/em&gt;&lt;/strong&gt;: Is it possible to test changes to it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Deliverability&lt;/em&gt;&lt;/strong&gt;: Is there a process to release changes to it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Persistency&lt;/em&gt;&lt;/strong&gt;: Will its data persist if the system is hindered?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Integrable&lt;/em&gt;&lt;/strong&gt;: Does it have a consistent and predictable interface allowing integration with it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Security&lt;/em&gt;&lt;/strong&gt;: Is it accessible only by the parts of the system that absolutely need it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Dependencies&lt;/em&gt;&lt;/strong&gt;: Are its dependencies fully tracked and managed?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common DevOps Team Pitfalls
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Pitfall:&lt;/em&gt;&lt;/strong&gt; DevOps work blocks developers work&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Indicator:&lt;/em&gt;&lt;/strong&gt; Developers need to wait for DevOps team changes to complete before continuing work&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Cause:&lt;/em&gt;&lt;/strong&gt; The DevOps team doesn't utilize its own practices (AKA shoemaker's son always goes barefoot)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Pitfall:&lt;/em&gt;&lt;/strong&gt; Only support developers and maintain the system&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Indicator:&lt;/em&gt;&lt;/strong&gt; No progress on any DevOps goal or task&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Cause:&lt;/em&gt;&lt;/strong&gt; Either there are no clear DevOps goals or repeating developers requests haven't been automated&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Pitfall:&lt;/em&gt;&lt;/strong&gt; Adopting 'Best' practices instead of 'Suitable' practices&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Indicator:&lt;/em&gt;&lt;/strong&gt; Introducing methodologies and adhering to principles that go against the company's goals&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Cause:&lt;/em&gt;&lt;/strong&gt; Prioritizing methodology over company goals, usually because of a disconnect from the company goals or due to lack of DevOps experience&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Pick a Team Shape That Fits Your Stage
&lt;/h2&gt;

&lt;p&gt;There's no single right structure, but these rules of thumb fit most startups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fewer than ~10 developers:&lt;/strong&gt; usually no dedicated DevOps hire yet. A developer who enjoys infrastructure, backed by a consultancy or a fractional DevOps engineer for the foundations, is often enough.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Around 10 to 20 developers:&lt;/strong&gt; time for the first DevOps engineer. Hire someone senior enough to set direction alone.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Beyond that:&lt;/strong&gt; a small platform team that treats the internal platform as a product, with the developers as its clients.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you grow, you'll choose between a central platform team and DevOps engineers embedded in product teams. Embedded engineers move fast but build one-off solutions; a platform team builds shared paths but can drift from developers' needs. A common middle ground: a platform team owns the shared platform, and each product team has a super user.&lt;/p&gt;

&lt;p&gt;Outside help makes sense when you need foundations fast, can't justify a full-time hire yet, or are still hiring. Insist that everything lives in Git so your team can own it. Here's &lt;a href="https://meteorops.com/blog/how-to-choose-a-devops-consulting-service" rel="noopener noreferrer"&gt;how to choose a DevOps consulting service&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calculate Your DevOps Team's Required Capacity
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.prod.website-files.com%2F6203daf47137054c031fa0e6%2F670d21d66de0b9f5f31ca107_670d2191598972f3f2d72b3d_Calculate%252520Your%252520DevOps%252520Team%252527s%252520Required%252520Capacity.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.prod.website-files.com%2F6203daf47137054c031fa0e6%2F670d21d66de0b9f5f31ca107_670d2191598972f3f2d72b3d_Calculate%252520Your%252520DevOps%252520Team%252527s%252520Required%252520Capacity.avif" alt="Calculate your DevOps team's required capacity" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Required DevOps Capacity = &lt;a href="https://meteorops.com/blog/calculating-your-companys-required-devops-capacity" rel="noopener noreferrer"&gt;(Scale * Complexity) / Leverage&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Leverage = Level of DevOps Engineers * Company Resources * Team Focus&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scale = Number of instances of each component * Number of people in the organization&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Complexity = Number of components * Number of teams&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hire the Right DevOps Engineers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.prod.website-files.com%2F6203daf47137054c031fa0e6%2F670d21d66de0b9f5f31ca101_670d21bd7f3e7e1228eea106_Hire%252520the%252520right%252520DevOps%252520Engineers.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.prod.website-files.com%2F6203daf47137054c031fa0e6%2F670d21d66de0b9f5f31ca101_670d21bd7f3e7e1228eea106_Hire%252520the%252520right%252520DevOps%252520Engineers.avif" alt="Hire the right DevOps engineers" width="799" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The types of DevOps Engineers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Barrels vs. Ammo&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
~ Ammo = People who can complete tasks but won't initiate them.&lt;br&gt;&lt;br&gt;
~ Barrel = People who understand what tasks are needed next but won't complete them.&lt;br&gt;&lt;br&gt;
Interviewer Tip: During the technical interview with a candidate ask about past DevOps accomplishments, and ask how the tasks were created and who did them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Aspiration-Oriented vs. Prevention-Oriented&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
~ Aspiration-Oriented = Has goals, positive feedback encourages and focuses them while negative feedback discourages them and kicks them off track.&lt;br&gt;&lt;br&gt;
~ Prevention-Oriented = Avoids problems, positive feedback makes them lay back and reduce capacity while negative feedback focuses them and keeps them on track.&lt;br&gt;&lt;br&gt;
Interviewer tip: See if there's a common theme for projects the candidate did in the past. People focused on security tasks and deep attention to specific details are more likely to be prevention-oriented, while people who initiated many projects spanning multiple (DevOps) categories are more likely to be aspiration-oriented.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://meteorops.com/blog/devops-agency-vs-devops-consultancy-vs-devops-services-company" rel="noopener noreferrer"&gt;Working with service providers&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set clear desired results&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
And let the DevOps service provider assist in exploring the goal and provide perspective from other companies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expect transparency on progress&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
And judge it against the latest plan.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expect clear planning&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
And make sure it has clear goals, takes into consideration the risks, and has a strategy that adheres to your DevOps principles.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How many DevOps engineers do I need?
&lt;/h3&gt;

&lt;p&gt;It depends on scale, complexity, and leverage. As a rule of thumb, one DevOps engineer can support roughly 10 to 20 developers when developers own their services and most work is automated. Less automation or more teams means more capacity; check it with the formula above.&lt;/p&gt;

&lt;h3&gt;
  
  
  What roles make up a DevOps team?
&lt;/h3&gt;

&lt;p&gt;Early on, one or two generalist DevOps engineers, with someone wearing the five DevOps Lead hats. As the team grows, people specialize by category (infrastructure, CI/CD, observability, security), and some teams add a reliability (SRE) focus.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should DevOps be a separate team?
&lt;/h3&gt;

&lt;p&gt;Only as a platform team that enables developers to own their services. It shouldn't become a team developers hand work over to, because that rebuilds the wall DevOps was meant to remove. If developers wait on DevOps tickets to ship, you've hit the first pitfall above.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should be in a DevOps team charter?
&lt;/h3&gt;

&lt;p&gt;The mission statement, the goals and principles that follow from it, and a definition of done. Add clear ownership boundaries: what the DevOps team owns, what developers own, and who is on call for what.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I hire DevOps engineers or outsource?
&lt;/h3&gt;

&lt;p&gt;Hire when there's steady, full-time DevOps work and you can attract someone senior enough to work without guidance. Use a consultancy or fractional engineer when you need foundations quickly, lack the expertise to judge candidates, or need to bridge the gap until a hire lands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We covered a lot in this one-pager, and still left plenty out.&lt;/p&gt;

&lt;p&gt;If you take away 1 thing from it, let it be this: A simple DevOps team mission statement is the most significant thing you need.&lt;/p&gt;

&lt;p&gt;It sounds simplistic and abstract, but without it there's no guiding principle for what DevOps in your organization should look like.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed, and send me an email at &lt;a href="mailto:michael@meteorops.com"&gt;michael@meteorops.com&lt;/a&gt; if there's anything else you'd like to see in here.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>management</category>
      <category>leadership</category>
      <category>startup</category>
    </item>
    <item>
      <title>Calculating your Company's Required DevOps Capacity</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Thu, 05 Nov 2026 07:30:08 +0000</pubDate>
      <link>https://dev.to/meteorops/calculating-your-companys-required-devops-capacity-1fbn</link>
      <guid>https://dev.to/meteorops/calculating-your-companys-required-devops-capacity-1fbn</guid>
      <description>&lt;p&gt;&lt;em&gt;This article was written by &lt;a href="https://meteorops.com/team/michael-zion" rel="noopener noreferrer"&gt;Michael Zion&lt;/a&gt;, CEO at MeteorOps, and first published on the &lt;a href="https://meteorops.com/blog/calculating-your-companys-required-devops-capacity" rel="noopener noreferrer"&gt;MeteorOps blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The capacity conversation usually starts after the workaround breaks
&lt;/h2&gt;

&lt;p&gt;A client recently asked the platform-engineering question that shows up when a company has grown past the “one senior engineer keeps delivery moving through heroics” stage. A handful of deployment scripts had turned into the operating layer for engineering: CI/CD workflows, cloud account and project structure, Kubernetes and serverless deployment paths, infrastructure-as-code modules, runtime standards, incident support, security guardrails, cost controls, secrets and access patterns, and the enablement work that stops teams from losing days to broken environments, unclear ownership, or knowledge trapped in chat threads.&lt;br&gt;&lt;br&gt;
The budget question was direct: why does this environment need three &lt;a href="https://meteorops.com/glossary/devops" rel="noopener noreferrer"&gt;DevOps&lt;/a&gt; engineers instead of one? The useful answer is not “because DevOps is important.” It is capacity math. Start with committed roadmap work, then add the operational load that rarely fits neatly into sprint planning: production escalations, pull request reviews, Terraform drift, failed pipelines, certificate and dependency updates, audit evidence, cost investigations, access requests, policy exceptions, flaky test infrastructure, base image patching, and the steady stream of “quick” developer support. In 2026, that background load is often heavier than the original platform plan assumed: more AI-assisted code reaching review, more short-lived environments, more compliance evidence, more cloud spend scrutiny, and more security checks pushed into the delivery path. If one engineer is expected to review infrastructure changes, unblock releases, tune cluster policies, handle on-call escalations, prepare audit artifacts, investigate cloud spend, and coach product teams through platform changes, staffing is no longer a preference debate. It is a business decision about how much delivery delay, burnout, single-point-of-failure risk, and platform instability the company is willing to carry in the system that ships and runs its software.&lt;/p&gt;

&lt;p&gt;Until that moment, the budget conversation had been relatively easy.&lt;br&gt;&lt;br&gt;
If storage utilization is climbing, you can show the graph and justify another few hundred dollars a month for disks.&lt;br&gt;&lt;br&gt;
If CI queues are delaying merges, deployments still require hand-holding, cloud accounts have weak guardrails, incidents are pulling senior engineers out of roadmap work, and product teams are waiting days for platform fixes, the case is harder to express. You are not buying “1.5 DevOps engineers”; you are buying release throughput, operational safety, faster recovery, cost control, compliance readiness, and fewer blocked engineers across the company.&lt;/p&gt;

&lt;p&gt;That is the gap these capacity formulas are meant to close. They take symptoms that usually arrive as scattered complaints — slow deployments, rising incident load, a platform backlog that never shrinks, fragile environments, security and compliance requests, cloud cost surprises, and constant support interruptions — and turn them into planning inputs that engineering, product, and finance can discuss without relying on the loudest anecdote in the room.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ Practical enough for planning, honest about uncertainty
&lt;/h2&gt;

&lt;p&gt;Use the formulas below as planning heuristics, not as a precise model of human work and not as a staffing ratio to copy from another company. A five-team SaaS business, a regulated enterprise, and a small product group built mostly on managed cloud services will make different assumptions about ownership, risk, automation, on-call coverage, compliance effort, lead time, and how much platform complexity they are willing to operate themselves.  &lt;/p&gt;

&lt;p&gt;The point is not to produce a magic number. The point is to make the constraints visible: where operational pressure is coming from, which teams are absorbing it, which roadmap work is being delayed, and what tradeoff the business is making if it chooses not to hire, reduce scope, standardize tooling, improve self-service, retire complexity, or simplify the platform. A useful capacity model should make the next decision clearer, even if the number is still an estimate.&lt;/p&gt;

&lt;p&gt;I call these formulas because they create a repeatable way to reason about capacity, not because engineering work can be measured with mathematical precision.&lt;br&gt;&lt;br&gt;
DevOps and platform work is shaped by interruptions, context switching, unclear ownership, production risk, and organizational friction. A useful model has to be simple enough for engineering managers, platform leads, and executives to use together, while still being honest enough to show where the pressure is really coming from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decisions this capacity model should help you make
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Help you understand how many DevOps Engineers you need&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provide you with tools to reason with your CFO&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encourage you to learn martial arts to successfully defeat your CFO in combat if all else fails&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🤷 Caveats
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;This model is not written in stone; &lt;a href="https://meteorops.com/blog/devops-agency-vs-devops-consultancy-vs-devops-services-company" rel="noopener noreferrer"&gt;I’m open to learning from your experience&lt;/a&gt; and improving it based on what you see in real engineering organizations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Calibrate the formulas before using the result&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Most of the formulas use inputs you can count: developers, services, environments, pipelines, incidents, and support channels. Those numbers are useful, but they do not explain the whole capacity picture. Qualitative factors such as ownership clarity, automation coverage, documentation quality, supportability, and maintenance debt can change the real capacity requirement as much as raw volume does. Ten services with consistent deployment patterns may be easier to support than three services with bespoke pipelines, unclear runbooks, and no obvious owner.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DevOps capacity is not the same as one full-time DevOps engineer&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Use the formulas without fooling yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Start by identifying what your current DevOps capacity can reliably support, then treat that as the baseline unit. For example:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;160 hours of DevOps engineering per month&lt;/strong&gt; = &lt;em&gt;20 microservices, 3 development teams, a defined release cadence, a known incident load, and a specific amount of platform support&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
The variables will differ by company, and the numbers only matter if they reflect real work. The point is to stop treating “one DevOps engineer” as a generic planning unit and instead measure the operating load that a given amount of capacity is carrying.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As the company grows, look for indicators the existing capacity isn’t able to handle more than it does and hire more DevOps capacity&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🚨 The indicators that more DevOps capacity is required
&lt;/h2&gt;

&lt;p&gt;There are 2 main indicators that more DevOps capacity is required:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Support work is useful until it becomes the platform interface&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Some support load is healthy. When the company is growing, the queue often shows where developers are getting stuck: unclear deployment paths, missing documentation, brittle environments, confusing access flows, or platform defaults that do not match real use.&lt;br&gt;&lt;br&gt;
The failure mode is different. If the same questions, access requests, deployment failures, and environment fixes keep coming back, support has stopped being discovery. It has become capacity leakage. At that point, DevOps-to-developer efficiency improves only when recurring support is converted into self-service, safer defaults, clearer ownership, or automation that removes the ticket altogether.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Different engineers and teams are solving the same problems in different ways for themselves.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This often starts when DevOps or platform hiring lags behind demand and developers cannot wait for every environment, pipeline, permission, or deployment issue to be handled centrally. Some local problem-solving is healthy, but it becomes expensive when every team builds its own scripts, Terraform patterns, CI templates, dashboards, or access workflows in isolation.&lt;br&gt;&lt;br&gt;
It is acceptable for product teams to solve DevOps use cases when those solutions become contributions to a shared platform or a documented standard. It is a warning sign when the same problem is being solved five different ways and none of those solutions are reusable, supportable, or owned.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example client indicators:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Company #1 example:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A company with roughly 300 developers had about 40 DevOps engineers spread across stateless infrastructure, data infrastructure, monitoring, CI/CD, and data streaming. Each group owned a Slack support channel. Over time, those channels became the default front door for pipeline failures, infrastructure questions, access requests, environment issues, and production follow-ups.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Capacity signal:&lt;/strong&gt; Several DevOps teams needed 1–3 engineers available mainly for support rotation. That was not just an on-call coverage issue. It showed that platform engineers had become a manual intake layer for work that should have been automated, documented, delegated, or exposed through self-service. The visible symptom was “too many questions in Slack”; the underlying capacity problem was that routine delivery work still required a specialist to interpret, approve, or execute it.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;What changed:&lt;/strong&gt; The teams reviewed recurring requests every week, grouped the highest-volume patterns, automated repeatable tasks, and created self-service paths for common developer needs. They also paired with key developers to move platform knowledge into product teams. The capacity gain did not come from asking DevOps engineers to work faster. It came from removing avoidable handoffs and making routine work executable without waiting for an answer in Slack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Company #2 example:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A company with 30 developers had one DevOps engineer supporting delivery, infrastructure, and developer requests.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Capacity signal:&lt;/strong&gt; The DevOps engineer spent most of their time on support tickets opened by developers. As common deployment errors kept recurring, some developers began bypassing the standard deployment process to keep work moving.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;What changed:&lt;/strong&gt; The company added monthly capacity through a part-time DevOps consultant and trained key developers to provide first-line support inside their teams. That combination reduced the single-person bottleneck without immediately turning every platform problem into a full-time hiring decision.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With those caveats in place, here is the planning model for estimating DevOps capacity.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical way to estimate DevOps capacity
&lt;/h2&gt;

&lt;p&gt;A useful way to estimate &lt;a href="https://meteorops.com/blog/how-to-build-a-devops-team" rel="noopener noreferrer"&gt;required DevOps capacity&lt;/a&gt; is to start with the work the platform team must absorb, then adjust for risk, complexity, and the level of self-service already in place:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsapj48likzoxo1r06rek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsapj48likzoxo1r06rek.png" alt="MeteorOps DevOps Capacity Formula" width="800" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this works as a planning model&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The bigger the stuff to build and maintain - the more working hands you need&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The more variations you need to support - the more working hands you need&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The more self-service you have, the fewer hands-on interruptions you should need&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive into the ingredients of scale, complexity, and leverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The baseline: what “DevOps capacity” actually includes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F60v8ek26esystg331y90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F60v8ek26esystg331y90.png" width="799" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The guiding principle here is simple: a DevOps engineer should enable delivery, not become a permanent checkpoint for every delivery task.&lt;br&gt;&lt;br&gt;
That means enabling teams to provision infrastructure, deploy workloads, store and process data, observe services, and recover from incidents with as little unnecessary handoff as possible. When every change still requires a DevOps engineer to approve, debug, click, or explain the same thing again, capacity is being consumed by friction rather than leverage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DevOps&lt;/strong&gt; = Enable ownership of the relevant stakeholders over the infrastructure, monitoring, security, architecture, data, configuration, deployment, orchestration, testing, and development.&lt;/p&gt;

&lt;p&gt;‘DevOps Capacity’ is the time &amp;amp; effort invested in achieving “DevOps” as defined above.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⛰️ Scale - Size Matters
&lt;/h2&gt;

&lt;p&gt;Start by defining the scale you are asking the platform to support. In capacity planning, “scale” is not only traffic volume. It also includes the number of services, environments, deployment paths, cloud accounts or projects, runtime patterns, data systems, compliance boundaries, and teams that depend on the platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fei44d2gtrwyh1vi0cmxx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fei44d2gtrwyh1vi0cmxx.png" width="798" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;“Michael, did you just create a recursive definition?”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why yes of course! this is the rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Larger systems require more time and effort to understand, build, secure, operate, and maintain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Larger teams and client bases create more internal and external use cases to support, which increases the load on platform, infrastructure, and release processes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To make the two types of scale above easier to discuss, I use two simple capacity models.&lt;br&gt;&lt;br&gt;
They are not scientific laws. They are structured ways to compare the demand created by your systems, teams, and operating model with the DevOps capacity your organization actually has:&lt;/p&gt;

&lt;h3&gt;
  
  
  Map the system scale and operational surface area
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo25ls4ttvib1the9cy7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo25ls4ttvib1the9cy7h.png" width="799" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resources Used&lt;/strong&gt; could mean many things, some of them are: Storage volume, Number of CPU cores, Number of nodes, Memory used, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;System throughput&lt;/strong&gt; is the work your systems process over time: user requests, scheduled jobs, batch runs, queue events, streaming workloads, and any other flow that creates operational load. Throughput matters because each flow tends to bring its own deployment risk, scaling pattern, observability requirement, failure mode, ownership boundary, and support expectation. A quiet batch job that fails every morning can consume more DevOps attention than a high-traffic service with mature dashboards, alerts, and rollback paths.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Instances per Service&lt;/strong&gt; refers to the number of replicas of the services developed within your company, for example: Kubernetes Pods, serverless functions executions, etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A client's system scale example: 1-year-old startup&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scale:&lt;/strong&gt; 3 AWS ECS clusters, 6 microservices, 3 main environments, 3–150 ephemeral development environments, and 6–40 container instances per environment&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Approach:&lt;/strong&gt; Infrastructure and deployments are managed with infrastructure as code. The company hired a part-time DevOps consultant to implement the initial system and train the development team to own routine changes, instead of creating a permanent dependency on the consultant for every deployment or environment issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Organization Scale
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fosu5dro6a3cqcag4g7pp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fosu5dro6a3cqcag4g7pp.png" width="798" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number of Developers&lt;/strong&gt; refers to the number of developers, and shame on you for bothering yourself with reading this line&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Total Users&lt;/strong&gt; refers to the number of active clients_&lt;br&gt;&lt;br&gt;
Noteworthy:&lt;br&gt;&lt;br&gt;
B2C will usually have more clients, with more standardized interfaces - DevOps Engineers most likely will be less involved in direct ways with client facing features.&lt;br&gt;&lt;br&gt;
B2B on the other hand will usually have less clients, with more customized interfaces per client - DevOps Engineers are more involved with client-facing features through the developers._&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Client's Organization Scale Example - Healthcare Company:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scale:&lt;/strong&gt; 200 developers divided into teams of 4–12 people, 10 DevOps engineers and SREs, high autonomy per team, and no single standardized process for all developers&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Approach:&lt;/strong&gt; Infrastructure and deployments are managed with infrastructure as code to support “one-click environments.” The company also used a part-time DevOps consultant to implement an initial system and train the development team to take ownership of it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bonus:&lt;/em&gt; &lt;a href="https://calendly.com/meteorops-solution-architects/30-minute-consultation" rel="noopener noreferrer"&gt;Check our availability&lt;/a&gt; for a call about scaling DevOps in your organization in a more gradual way using MeteorOps.&lt;/p&gt;

&lt;h2&gt;
  
  
  🥴 Complexity - More Options, Less Clarity
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq0ituwt5brt1z3bugxkj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq0ituwt5brt1z3bugxkj.png" width="796" height="103"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I know, I know… It looks similar to the chapter about Scale.&lt;/p&gt;

&lt;p&gt;In this context, complexity is not only the number of systems you run. It is the number of choices engineers must make without strong defaults, and the uncertainty around which path is considered safe, supported, and maintainable. That uncertainty creates decision latency and makes it more likely that two teams solve the same problem in different, incompatible ways.&lt;br&gt;&lt;br&gt;
You are operating in a complex environment when an engineer knows what outcome they want, but still has to ask, “Is this how we do it here?”&lt;/p&gt;

&lt;h3&gt;
  
  
  So, what does complexity have to do with both the system and the organization?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;More complex system - More time and effort are required to map the available options, and customize (copy, paste, modify) or generalize (refactor, parameterize) solutions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More complex organization - More time and effort are required to communicate, provide support, cascade initiatives through the company, and lower likelihood of initiatives getting accepted&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This time I’ll present you with the formulas for complexity without drumrolls:&lt;/p&gt;

&lt;h3&gt;
  
  
  System Complexity
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkiv9aukk8yswgeu1sfgn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkiv9aukk8yswgeu1sfgn.png" width="800" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number of Tools&lt;/strong&gt; refers to any tool, either existing or custom-built, that helps build and maintain the system. More tools mean more capabilities, more potential integrations between tools, and more potential ways to achieve the same goals. (Tools have an upside as well!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number of Platforms&lt;/strong&gt; means any platform on which you run workloads or consume resources (e.g. - AWS, Kubernetes, Linux, Jenkins). Using more platforms requires supporting more ways of running each workload or consuming each resource.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number of Codebases&lt;/strong&gt; refers to the repositories where your systems are developed and maintained. The more separate codebases you operate, the harder it becomes to keep development workflows consistent: build conventions drift, CI/CD pipelines fork, dependency upgrades happen unevenly, and release practices become harder to support at scale. A larger number of repositories does not automatically mean you need more DevOps capacity, but it does increase the value of shared templates, standards, and automation that prevent every team from reinventing the same delivery path.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number of Services&lt;/strong&gt; is the number of services developed by the developers: more services, more different units with different logic to them, which in turn creates more unique operational requirements.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To sum up, ‘System Complexity’ increases when there are more services, running on more platforms, managed by more tools, across more codebases.&lt;/p&gt;

&lt;p&gt;A Client's System Complexity Example - Low Scale, High Complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity:&lt;/strong&gt; The entire system was 1 service deployed on just 1 server, but was deployed using multiple deployment tools (chef, ansible, bash scripts), from multiple different repositories (about 10), with a specific set of steps required to fully set it up
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approach:&lt;/strong&gt; Containerize everything, Consolidate the deployment to one docker-compose file, Consolidate the configuration and automation to one tool (ansible), Consolidate the repositories into one&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Organization Complexity
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmxd1ckd6zsiqmvxwuq8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmxd1ckd6zsiqmvxwuq8p.png" width="799" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number of Teams&lt;/strong&gt; - More teams mean supporting and maintaining more ways of work&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number of Hierarchy Levels&lt;/strong&gt; - More middle-management layers in the organization make it more likely decisions and communication will cascade through it, and so increasing the time &amp;amp; effort for decision-making and communication&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Level of Hierarchy-Reliance for Communication&lt;/strong&gt; - Exactly the same effect, but focused on the culture of the company&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🪄 Is there anything that makes DevOps capacity more efficient?
&lt;/h2&gt;

&lt;p&gt;Calculating DevOps capacity is not just a headcount exercise. Done well, it exposes where delivery is actually getting stuck: repeated support requests, fragile release paths, manual environment provisioning, unclear ownership, noisy incident handoffs, and the morale cost of constant interruption.&lt;br&gt;&lt;br&gt;
The better planning question is not “how many DevOps engineers do we need?” It is “which constraint should the next unit of capacity remove?” In many organizations, adding another person to absorb tickets only makes the bottleneck quieter for a while. The higher-leverage move may be self-service environment creation, paved-road CI/CD templates, standardized cloud and Kubernetes defaults, documented escalation paths, workable access flows, or clearer ownership boundaries that show when a product team can act independently and when platform help is required. If the discussion is stuck in anecdotes, a structured &lt;a href="https://meteorops.com/assessments/devops-maturity" rel="noopener noreferrer"&gt;DevOps maturity assessment&lt;/a&gt; can give teams a shared language for deciding what to automate, what to standardize, what to delegate, and where specialist DevOps or platform engineering capacity still matters. The goal is not to keep the platform team busy. It is to make the same capacity support more teams, safer releases, and faster recovery without turning that team into the permanent approval queue for every deployment, pipeline change, cloud request, access issue, or post-incident follow-up.&lt;/p&gt;

&lt;p&gt;Valid question! And this is the formula for DevOps ‘Leverage’:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fklq5dwtczll9n3nkg0ly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fklq5dwtczll9n3nkg0ly.png" width="800" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Documentation Coverage&lt;/strong&gt; - Out of the internal company’s tools and processes, what percentage has documentation?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automated Processes Coverage&lt;/strong&gt; - Out of the manual processes used by the developers, what percentage was automated?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Engineering Talent Concentration Score&lt;/strong&gt; - The seniority (relevant experience) of your engineering team, divided by the acceptance rate of engineers to your company.&lt;br&gt;&lt;br&gt;
More experience and lower acceptance rates improve the score.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tools Community Size&lt;/strong&gt; - How widely adopted are the tools being used by the company? And how active is the open community working on and with it?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example:
&lt;/h3&gt;

&lt;p&gt;Another client of ours had all of its infrastructure managed manually.&lt;br&gt;&lt;br&gt;
To increase the documentation-coverage and the automated-processes-coverage, it decided to adopt an infrastructure-as-code tool.&lt;br&gt;&lt;br&gt;
They considered Terraform and Pulumi, and ended up choosing Pulumi, in order to avoid hiring more full-time DevOps Engineers, and delegate responsibilities for infrastructure management to the developers.&lt;br&gt;&lt;br&gt;
It increased the documentation-coverage by the sheer fact that all of the infrastructure is now described in a Git repository.&lt;br&gt;&lt;br&gt;
It increased the automated-processes-coverage because every piece of new infrastructure was introduced into Git, would exist in every new environment, and would get automatically reconciled if its state drifts.&lt;/p&gt;

&lt;p&gt;And the formula for the score (One last formula, I promise):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fofhlyxu6xym0xalso1f5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fofhlyxu6xym0xalso1f5.png" width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that this variable does NOT say “&lt;strong&gt;DevOps&lt;/strong&gt; Engineering Talent Concentration Score”, because the assumptions are that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Every engineer on the team can take part in filling the DevOps capacity - it doesn’t have to be a specific team or person&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More experienced engineers require less training and support, and so consume less time for the DevOps Capacity&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example:
&lt;/h3&gt;

&lt;p&gt;MeteorOps hires 7 engineers out of every 1,000 vetted.&lt;br&gt;&lt;br&gt;
We only vet DevOps Engineers with extensive production experience in at least two previous companies.&lt;br&gt;&lt;br&gt;
Our median seniority is 8 years of experience.&lt;br&gt;&lt;br&gt;
It means the ETCS (Engineering Talent Concentration Score) is 114.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Engineering Talent Concentration Score - The biggest leverage you can get
&lt;/h2&gt;

&lt;p&gt;If you can take only one thing from this article, make it the engineering talent score.&lt;/p&gt;

&lt;p&gt;Having a DevOps candidates pool of engineers with relevant experience, and hiring only the top percentile of that pool, is an insanely high-leverage action.&lt;/p&gt;

&lt;p&gt;You get engineers with perspective on how to do things right, and perhaps more importantly, how to do things wrong.&lt;br&gt;&lt;br&gt;
Enjoying someone’s learning from successes, and learning from failures, saves your company lots of time learning the hard way.&lt;/p&gt;

&lt;p&gt;External DevOps help can be useful, but it should be framed as a capacity and capability decision, not a way to postpone operating-model choices. A good partner reduces bottlenecks by building reusable platform patterns, documenting how the system is supposed to run, tightening delivery and runtime practices, and transferring knowledge back to the teams that will own the work later. If the engagement simply adds more hands to the same ticket queue, you may buy short-term relief while the underlying capacity problem keeps compounding. Use outside support when it is tied to a concrete outcome: stabilizing delivery, creating self-service infrastructure, improving cloud or Kubernetes operations, lowering incident load, or covering a specialist gap while you hire, train, or reorganize internally.&lt;/p&gt;

&lt;p&gt;I’m not going to do that.&lt;/p&gt;

&lt;p&gt;(P.S. - I’m the Marketing Director)&lt;/p&gt;

&lt;h2&gt;
  
  
  To Summarize
&lt;/h2&gt;

&lt;p&gt;Instead of writing more words, here are all of the formulas:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsapj48likzoxo1r06rek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsapj48likzoxo1r06rek.png" width="800" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F60v8ek26esystg331y90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F60v8ek26esystg331y90.png" width="799" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fei44d2gtrwyh1vi0cmxx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fei44d2gtrwyh1vi0cmxx.png" width="798" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo25ls4ttvib1the9cy7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo25ls4ttvib1the9cy7h.png" width="799" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fosu5dro6a3cqcag4g7pp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fosu5dro6a3cqcag4g7pp.png" width="798" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq0ituwt5brt1z3bugxkj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq0ituwt5brt1z3bugxkj.png" width="796" height="103"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkiv9aukk8yswgeu1sfgn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkiv9aukk8yswgeu1sfgn.png" width="800" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmxd1ckd6zsiqmvxwuq8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmxd1ckd6zsiqmvxwuq8p.png" width="799" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fklq5dwtczll9n3nkg0ly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fklq5dwtczll9n3nkg0ly.png" width="800" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fofhlyxu6xym0xalso1f5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fofhlyxu6xym0xalso1f5.png" width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you find it useful!&lt;/p&gt;

&lt;p&gt;I’m also interested in learning about how you used he formulas, and what insights you had as a result.&lt;br&gt;&lt;br&gt;
If you came up with new useful variables and formulas, please send it to me so I can take credit over inventing them.&lt;/p&gt;

&lt;h2&gt;
  
  
  If your CFO isn’t convinced
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.prod.website-files.com%2F6203daf47137054c031fa0e6%2F66c383514085711c57db3b6e_66c383489c36d6b1ec181729_If%252520your%252520CFO%252520isn%2525E2%252580%252599t%252520convinced.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.prod.website-files.com%2F6203daf47137054c031fa0e6%2F66c383514085711c57db3b6e_66c383489c36d6b1ec181729_If%252520your%252520CFO%252520isn%2525E2%252580%252599t%252520convinced.avif" alt="If your CFO isn't convinced: two boxers squaring up" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>management</category>
      <category>leadership</category>
      <category>startup</category>
    </item>
    <item>
      <title>Terraform Project Structure: 3 Layouts That Scale</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Wed, 04 Nov 2026 07:30:09 +0000</pubDate>
      <link>https://dev.to/meteorops/terraform-project-structure-3-layouts-that-scale-3b41</link>
      <guid>https://dev.to/meteorops/terraform-project-structure-3-layouts-that-scale-3b41</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide was written by &lt;a href="https://meteorops.com/team/michael-zion" rel="noopener noreferrer"&gt;Michael Zion&lt;/a&gt;, CEO at MeteorOps, and first published on the &lt;a href="https://meteorops.com/blog/how-to-structure-terraform-for-startup-scale" rel="noopener noreferrer"&gt;MeteorOps blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;A good Terraform project structure keeps reusable modules separate from the root modules that deploy them, gives every environment and major component its own state file, and pins provider and module versions. Start with one directory per environment, split state by blast radius as you grow, and add Terragrunt only when duplication actually hurts.&lt;/p&gt;

&lt;p&gt;Most guides stop at "put variables in variables.tf". That is the easy part. The decisions that matter are how you split state, how environments differ without copy-paste drift, how changes are reviewed and applied, and when to change the layout as the team grows. This guide covers all of them with three reference layouts you can copy, sized for teams of roughly 1 to 5, 5 to 20, and 20 to 50 engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform project structure basics: files and modules
&lt;/h2&gt;

&lt;p&gt;Inside any single Terraform directory, follow HashiCorp's &lt;a href="https://developer.hashicorp.com/terraform/language/style" rel="noopener noreferrer"&gt;Terraform style guide&lt;/a&gt; file names. They are boring on purpose: anyone opening the directory knows where to look.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;What goes in it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;terraform.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;terraform&lt;/code&gt; block with &lt;code&gt;required_version&lt;/code&gt; and &lt;code&gt;required_providers&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;providers.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All &lt;code&gt;provider&lt;/code&gt; blocks and their configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;backend.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The backend configuration (where state lives)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;main.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resource and data source blocks (split into topic files such as &lt;code&gt;network.tf&lt;/code&gt; or &lt;code&gt;iam.tf&lt;/code&gt; when it gets long)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;variables.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Variable blocks, in alphabetical order&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputs.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Output blocks, in alphabetical order&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;locals.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Local values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.terraform.lock.hcl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Provider dependency lock file; commit it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The more important distinction is between two kinds of directories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Child modules&lt;/strong&gt; are reusable building blocks (a VPC, a database, a service). They take variables, create resources and return outputs. They have no backend and no provider configuration of their own.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Root modules&lt;/strong&gt; are the directories you actually run &lt;code&gt;terraform plan&lt;/code&gt; and &lt;code&gt;apply&lt;/code&gt; in. Each root module has its own backend and therefore its own state file. A root module is a unit of deployment, and its state is its blast radius.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else in this guide follows from that: &lt;strong&gt;your directory layout is really a decision about how many root modules you have and what each one owns.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1leqsafkicczuv8r9ct.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1leqsafkicczuv8r9ct.webp" alt="Diagram: child modules such as VPC, database and service are reusable building blocks with no backend or provider config; root modules such as staging and production call them, are where you run plan and apply, and each has its own state file, which is its blast radius." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Each root module owns one state file, so your layout decides how much one plan can break.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Three Terraform project layouts compared
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layout&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;State split&lt;/th&gt;
&lt;th&gt;Main risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Directory per environment&lt;/td&gt;
&lt;td&gt;1 to 5 engineers, one cloud account per environment&lt;/td&gt;
&lt;td&gt;One state per environment&lt;/td&gt;
&lt;td&gt;Every plan touches everything in that environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Modules plus live, split by component&lt;/td&gt;
&lt;td&gt;5 to 20 engineers, several services and accounts&lt;/td&gt;
&lt;td&gt;One state per environment per component&lt;/td&gt;
&lt;td&gt;Copy-paste of backend and provider config across directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Terragrunt hierarchy&lt;/td&gt;
&lt;td&gt;20 to 50 engineers, many accounts and regions&lt;/td&gt;
&lt;td&gt;One state per unit, generated backends&lt;/td&gt;
&lt;td&gt;An extra tool and more indirection to learn&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Layout 1: one directory per environment
&lt;/h3&gt;

&lt;p&gt;This is the layout HashiCorp recommends when you are not using HCP Terraform workspaces: each environment gets its own directory and state, and shared code lives in local modules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;infra/
  modules/
    network/
      main.tf
      variables.tf
      outputs.tf
    service/
      main.tf
      variables.tf
      outputs.tf
  environments/
    staging/
      backend.tf
      providers.tf
      terraform.tf
      main.tf          # calls ../../modules/network and ../../modules/service
      terraform.tfvars
    production/
      backend.tf
      providers.tf
      terraform.tf
      main.tf
      terraform.tfvars
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is easy to read, easy to review, and each environment can only break itself. The cost shows up as the environment grows: a single production state with a few hundred resources means slow plans, lock contention when two people need to change unrelated things, and a scary diff every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layout 2: modules plus live, split by component
&lt;/h3&gt;

&lt;p&gt;When plans get slow or different people own different parts of the infrastructure, split each environment into components with their own state. The common split is by layer, ordered by how often things change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;infra/
  modules/                 # versioned building blocks
    vpc/
    eks-cluster/
    rds-postgres/
    service/
  live/
    staging/
      network/             # VPC, subnets, NAT, DNS zones
      data/                # databases, caches, buckets
      cluster/             # Kubernetes cluster and add-ons
      services/
        api/
        worker/
    production/
      network/
      data/
      cluster/
      services/
        api/
        worker/
  global/
    iam/                   # org-wide roles, SSO, CI identities
    dns/                   # registrar-level and shared zones
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each leaf directory is a root module with its own backend key, such as &lt;code&gt;production/data/terraform.tfstate&lt;/code&gt;. Changing a service no longer locks or plans the network. Losing or corrupting one state file affects one component. Ownership maps cleanly to CODEOWNERS rules on directories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layout 3: Terragrunt with an account, region and environment hierarchy
&lt;/h3&gt;

&lt;p&gt;With many accounts and regions, layout 2 turns into dozens of nearly identical &lt;code&gt;backend.tf&lt;/code&gt; and &lt;code&gt;providers.tf&lt;/code&gt; files. Terragrunt removes that duplication by generating them from a hierarchy of configuration files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;live/
  root.hcl                  # remote state and provider generation, shared by all units
  prod-account/
    account.hcl             # account id, account name
    eu-west-1/
      region.hcl
      production/
        env.hcl
        network/terragrunt.hcl
        data/terragrunt.hcl
        cluster/terragrunt.hcl
  staging-account/
    account.hcl
    eu-west-1/
      region.hcl
      staging/
        env.hcl
        network/terragrunt.hcl
        data/terragrunt.hcl
        cluster/terragrunt.hcl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A unit's &lt;code&gt;terragrunt.hcl&lt;/code&gt; points at a versioned module and supplies only its inputs and dependencies. Terragrunt can also run many units in dependency order. We published a ready-to-use example in our &lt;a href="https://meteorops.com/blog/terraform-starter-boilerplate-for-gcp-using-terragrunt" rel="noopener noreferrer"&gt;Terraform starter boilerplate for GCP using Terragrunt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Adopt Terragrunt when the duplication is real, not on day one. A team of three with two environments gets more confusion than value from it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about workspaces and Terraform Stacks?
&lt;/h3&gt;

&lt;p&gt;Two features often come up as alternatives to directories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CLI workspaces&lt;/strong&gt; (&lt;code&gt;terraform workspace new staging&lt;/code&gt;) keep several states for one configuration in one backend. HashiCorp's &lt;a href="https://developer.hashicorp.com/terraform/cli/workspaces" rel="noopener noreferrer"&gt;workspace documentation&lt;/a&gt; says they are not a suitable isolation mechanism when deployments need different credentials and access controls, and are not a tool for system decomposition. Use them for short-lived copies (a feature branch test), not for staging versus production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HCP Terraform workspaces&lt;/strong&gt; are a different thing: each is a separate state with its own variables, permissions and runs. If you use HCP Terraform, one workspace per environment and component is the recommended pattern.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Terraform Stacks&lt;/strong&gt; in HCP Terraform let you define components once and deploy them to many environments, regions or accounts. HashiCorp &lt;a href="https://www.hashicorp.com/en/blog/scale-infrastructure-with-new-terraform-and-packer-features-at-hashiconf-2025" rel="noopener noreferrer"&gt;announced general availability at HashiConf 2025&lt;/a&gt;. Consider them if you are already on HCP Terraform and repeat the same infrastructure across many deployments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to split Terraform state by blast radius
&lt;/h2&gt;

&lt;p&gt;The right number of state files is the smallest number that keeps each one safe to change. These are the boundaries that matter, in roughly the order teams need them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Environment.&lt;/strong&gt; Production and non-production never share a state, and ideally never share a cloud account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Account or project.&lt;/strong&gt; One state per cloud account or GCP project keeps credentials simple.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Change frequency.&lt;/strong&gt; Networking changes a few times a year; services change weekly. Do not make a service deploy plan the VPC.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data versus stateless resources.&lt;/strong&gt; Databases and buckets deserve their own state with &lt;code&gt;prevent_destroy&lt;/code&gt; on critical resources, so a refactor in a service directory cannot touch them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ownership.&lt;/strong&gt; If two teams change different resources, give them different states so they do not block each other's locks or reviews.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp968aqqcjjsqdehbcgzb.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp968aqqcjjsqdehbcgzb.webp" alt="Staircase of five boundaries for splitting Terraform state, in roughly the order teams need them: environment, account or project, change frequency (network yearly, services weekly), data versus stateless resources, and ownership." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Add state boundaries in this order as the team and infrastructure grow.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Signals that a state is too big: plans take more than a couple of minutes, unrelated changes queue on the lock, or reviewers stop reading the plan output. Signals that you split too far: every change needs coordinated applies across five directories, or you spend more time wiring outputs between states than writing resources.&lt;/p&gt;
&lt;h2&gt;
  
  
  Remote state, locking and backend configuration
&lt;/h2&gt;

&lt;p&gt;Never keep state on a laptop or in Git. Use a remote backend with locking, encryption and versioning turned on.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cloud&lt;/th&gt;
&lt;th&gt;Backend&lt;/th&gt;
&lt;th&gt;Locking&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AWS&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;s3&lt;/code&gt; with bucket versioning and encryption&lt;/td&gt;
&lt;td&gt;S3 lock file with &lt;code&gt;use_lockfile = true&lt;/code&gt; (Terraform 1.10 and later); DynamoDB locking is deprecated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Cloud&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gcs&lt;/code&gt; with object versioning&lt;/td&gt;
&lt;td&gt;Built in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;azurerm&lt;/code&gt; storage account&lt;/td&gt;
&lt;td&gt;Built in, using blob leases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;HCP Terraform, Spacelift, env0, Scalr&lt;/td&gt;
&lt;td&gt;Managed by the platform&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;An S3 backend for the layout 2 example looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform {
  backend "s3" {
    bucket       = "acme-terraform-state-prod"
    key          = "production/data/terraform.tfstate"
    region       = "eu-west-1"
    encrypt      = true
    use_lockfile = true
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://developer.hashicorp.com/terraform/language/backend/s3" rel="noopener noreferrer"&gt;S3 backend documentation&lt;/a&gt; notes that locking is opt in and that DynamoDB-based locking is deprecated. If you are migrating, you can set both during the transition and run &lt;code&gt;terraform init -reconfigure&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Keep one state bucket per account (or at least separate production), restrict who can read it (state contains secrets such as generated passwords), and turn on versioning so you can recover from a bad write.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sharing values between states
&lt;/h3&gt;

&lt;p&gt;Once state is split, components need each other's values: the cluster needs subnet IDs, services need the database endpoint. You have three options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data sources&lt;/strong&gt; that look up real resources by tag or name (for example &lt;code&gt;data "aws_vpc"&lt;/code&gt;). Loosely coupled and our default.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Published parameters&lt;/strong&gt;: one component writes outputs to AWS Systems Manager Parameter Store or a similar store, and others read them. Explicit and permission-controlled.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;terraform_remote_state&lt;/code&gt;&lt;/strong&gt;: reads another state's outputs directly. Simple, but it requires read access to the whole state file, which can expose secrets.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgwr82papsgag7b1owe86.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgwr82papsgag7b1owe86.webp" alt="Three ways to share values between Terraform states: data sources that look up real resources by tag or name (loosely coupled, the default), published parameters in a store such as Parameter Store (explicit and permission-controlled), and terraform_remote_state, which needs read access to the whole other state file." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Prefer lookups and published parameters; remote state reads expose the whole state file.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Module versioning and pinning
&lt;/h2&gt;

&lt;p&gt;Pin everything that can change underneath you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform {
  required_version = "&amp;gt;= 1.10"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~&amp;gt; 6.0"
    }
  }
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~&amp;gt; 6.0"
  # ...
}

module "api" {
  source = "git::https://github.com/acme/terraform-modules.git//service?ref=v2.4.1"
  # ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Registry modules take a &lt;code&gt;version&lt;/code&gt; argument; Git modules use &lt;code&gt;?ref=&lt;/code&gt; with a tag.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit &lt;code&gt;.terraform.lock.hcl&lt;/code&gt; so every run uses the same provider builds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Version your own modules with tags and a changelog once more than one root module uses them. Upgrade staging first, then production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Local modules (&lt;code&gt;source = "../../modules/vpc"&lt;/code&gt;) cannot be versioned. That is fine in layout 1, but it means every environment gets every module change at once.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Naming and conventions that keep a codebase readable
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use snake_case for resource names and do not repeat the resource type (&lt;code&gt;aws_s3_bucket.assets&lt;/code&gt;, not &lt;code&gt;aws_s3_bucket.assets_bucket&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Put environment, service and owner in default tags or labels at the provider level, so every resource is attributable for cost and incidents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Give variables types, descriptions and validation; avoid huge untyped &lt;code&gt;map(any)&lt;/code&gt; inputs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep environment differences in &lt;code&gt;.tfvars&lt;/code&gt; or inputs (instance sizes, replica counts), not in conditional logic scattered through modules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;terraform fmt&lt;/code&gt; and &lt;code&gt;terraform validate&lt;/code&gt; in CI, plus a linter such as TFLint and a policy scanner such as Checkov or Trivy.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  CI/CD for Terraform: plan on pull request, apply on merge
&lt;/h2&gt;

&lt;p&gt;Your structure only works if changes flow through review. The pattern that holds up at every size:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A pull request triggers &lt;code&gt;terraform plan&lt;/code&gt; for every root module whose files (or whose modules) changed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The plan output is posted to the pull request for review.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Merging to &lt;code&gt;main&lt;/code&gt; applies the reviewed plan, with a manual approval for production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CI authenticates with short-lived OpenID Connect (OIDC) credentials, not stored cloud keys. Plan jobs get read-only roles; apply jobs get write roles limited to their account.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6skjhrqedjy0752tiass.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6skjhrqedjy0752tiass.webp" alt="Flow: a pull request triggers terraform plan for each changed root module, the plan is posted for review, and merging to main applies it with manual approval for production; plan uses an OIDC read-only role and apply uses an OIDC write role, with short-lived credentials and no stored cloud keys." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Reviewers approve the exact plan that gets applied, and CI never holds long-lived keys.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A minimal GitHub Actions plan job for one root module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: terraform-plan
on:
  pull_request:
    paths:
      - "infra/live/production/data/**"
      - "infra/modules/rds-postgres/**"

permissions:
  id-token: write
  contents: read
  pull-requests: write

jobs:
  plan:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: infra/live/production/data
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/terraform-plan
          aws-region: eu-west-1
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init -input=false
      - run: terraform plan -input=false -no-color -out=tfplan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hand-written path filters break down past a few dozen root modules. At that point use a tool built for it: Atlantis or Digger (self-hosted, pull request driven), Terragrunt's run commands, or a managed platform such as HCP Terraform, Spacelift or env0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring an existing Terraform codebase safely
&lt;/h2&gt;

&lt;p&gt;Most teams reading this already have a structure they want to change. Terraform has declarative tools for this, so you rarely need to edit state by hand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;moved&lt;/code&gt; blocks&lt;/strong&gt; rename resources or move them into modules within the same state, and show the move in the plan.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;import&lt;/code&gt; blocks&lt;/strong&gt; (Terraform 1.5 and later) bring existing resources under management, which is how you move a resource into a new state: import it in the new root module, then remove it from the old one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;removed&lt;/code&gt; blocks&lt;/strong&gt; (Terraform 1.7 and later) drop resources from state without destroying them, using &lt;code&gt;lifecycle { destroy = false }&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Split one component at a time, and confirm that both the old and new root modules plan with no changes before moving on. Back up the state files first; with bucket versioning you also get a rollback path.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsfv8oa8fo0hnqzuf6lcd.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsfv8oa8fo0hnqzuf6lcd.webp" alt="Steps to move a database resource from an old root module to a new one: back up both state files, add an import block in the new root module, add a removed block with destroy = false in the old one, and confirm both plan with no changes; split one component at a time." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Import first, remove without destroying, and only move on when both sides plan clean.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Terraform structure mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;One giant state for everything.&lt;/strong&gt; Slow plans, lock queues, and a production database in the same blast radius as a DNS record.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Copying environments instead of calling modules.&lt;/strong&gt; Staging and production drift apart within weeks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using CLI workspaces for production isolation.&lt;/strong&gt; Same backend, same credentials, one wrong &lt;code&gt;terraform workspace select&lt;/code&gt; away from an incident.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unpinned providers and modules.&lt;/strong&gt; A routine plan suddenly shows changes nobody made.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Applying from laptops.&lt;/strong&gt; No review, no audit trail, and state drift when two people apply at once.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deeply nested modules.&lt;/strong&gt; Modules that call modules that call modules make plans unreadable. Keep it to one or two levels.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Click-ops fixes during incidents that never get imported.&lt;/strong&gt; Reconcile drift weekly with scheduled plans.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Terraform project structure checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Child modules and root modules live in separate directories (or repositories).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Production has its own state, credentials and ideally its own cloud account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each state covers one environment and one component with a clear owner.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remote backend with locking, encryption and versioning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Terraform, provider and module versions pinned; lock file committed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plans run on pull requests; applies happen from CI after review.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CI uses OIDC roles, read-only for plan.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Default tags or labels on every resource.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scheduled drift detection.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Terraform project structure FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the best folder structure for Terraform?
&lt;/h3&gt;

&lt;p&gt;Separate reusable modules from root modules, and give each environment its own root module and state. Small teams can use one directory per environment; growing teams split each environment into components such as network, data, cluster and services. Add Terragrunt when backend and provider configuration is duplicated across many directories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I use a monorepo or multiple repositories for Terraform?
&lt;/h3&gt;

&lt;p&gt;A monorepo is simpler for small teams because modules and environments change together in one pull request. HashiCorp's style guide recommends separate repositories for modules once they are shared widely, because tags and access control work per repository. Many teams keep a modules repository and a live infrastructure repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I use Terraform workspaces for environments?
&lt;/h3&gt;

&lt;p&gt;Not CLI workspaces. They share one backend and credentials, which HashiCorp's own documentation says is unsuitable when deployments need separate access controls. HCP Terraform workspaces are different and are a good way to separate environments if you use that platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many resources should one Terraform state hold?
&lt;/h3&gt;

&lt;p&gt;There is no fixed number. Split a state when plans become slow, when unrelated changes wait on the same lock, or when critical data resources share a state with frequently changed services. Many healthy states hold tens to a few hundred resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  When should I use Terragrunt?
&lt;/h3&gt;

&lt;p&gt;Use Terragrunt when you manage many environments, accounts or regions and keep copying the same backend, provider and input configuration. For a small team with two environments, plain Terraform with a directory per environment is easier to understand.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I share outputs between Terraform states?
&lt;/h3&gt;

&lt;p&gt;Prefer data sources that look up resources by name or tag, or publish values to a parameter store. The &lt;code&gt;terraform_remote_state&lt;/code&gt; data source also works but requires read access to the other state file, which may contain secrets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does this structure work with OpenTofu?
&lt;/h3&gt;

&lt;p&gt;Yes. OpenTofu uses the same configuration language, module and backend model, so the layouts, state splitting and CI pattern apply unchanged. Check feature-level differences such as backend options against the OpenTofu documentation.&lt;/p&gt;

&lt;p&gt;For the bigger picture of where Terraform fits next to CI/CD, GitOps and observability tools, see our guide to &lt;a href="https://meteorops.com/blog/how-to-choose-the-right-devops-tools-for-your-team" rel="noopener noreferrer"&gt;DevOps tools by category&lt;/a&gt;. If you want senior engineers to restructure an existing Terraform codebase with your team, &lt;a href="https://meteorops.com/devops-setup-for-production-free-consultation" rel="noopener noreferrer"&gt;book a free DevOps setup consultation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>devops</category>
      <category>aws</category>
      <category>cicd</category>
    </item>
    <item>
      <title>On-Call Rotation: How to Design a Schedule for Small Teams</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Tue, 03 Nov 2026 07:30:10 +0000</pubDate>
      <link>https://dev.to/meteorops/on-call-rotation-how-to-design-a-schedule-for-small-teams-1hoh</link>
      <guid>https://dev.to/meteorops/on-call-rotation-how-to-design-a-schedule-for-small-teams-1hoh</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide was written by &lt;a href="https://meteorops.com/team/arthur-azrieli" rel="noopener noreferrer"&gt;Arthur Azrieli&lt;/a&gt;, CTO at MeteorOps, and first published on the &lt;a href="https://meteorops.com/blog/how-to-design-on-call-before-you-hire-sre" rel="noopener noreferrer"&gt;MeteorOps blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;An on-call rotation is a schedule that names one engineer (the primary) to answer production pages for a fixed period, usually one week, with a secondary as backup and a clear escalation path above them. For a small team, the right rotation is weekly primary and secondary, paging only on customer impact, with written handoffs and runbooks.&lt;/p&gt;

&lt;p&gt;You do not need a Site Reliability Engineering (SRE) team to run on-call well. You need named owners, a schedule people can actually sustain, alerts that only fire when a human must act, and an escalation policy that gets the right person involved without a debate at 3 a.m. This guide covers each of those for teams of 3 to 15 engineers: rotation types, team-size math, escalation rules, paging hygiene, handoffs, compensation and tooling, plus a schedule template you can copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  On-call rotation basics: primary, secondary and escalation
&lt;/h2&gt;

&lt;p&gt;Every working rotation has the same three layers, whatever tool you use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Primary on-call:&lt;/strong&gt; receives every page first, acknowledges it, and owns the first response: triage, mitigation, and calling for help.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Secondary on-call:&lt;/strong&gt; is paged automatically if the primary does not acknowledge in time, and joins any incident that needs a second pair of hands.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Escalation contact:&lt;/strong&gt; usually an engineering lead or CTO, who joins for customer-facing outages, security incidents, and decisions with business risk such as rolling back a migration or putting the product into read-only mode.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A shift is the period one person holds the primary pager. The rotation is the order in which people take shifts. The schedule is the rotation laid out on a calendar with overrides for holidays and sick days. When people search for "on call schedule" they usually want the last one, so there is a template further down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rotation types compared
&lt;/h2&gt;

&lt;p&gt;Pick the rotation type from your team size and where your engineers live, not from what a large company does. These are the patterns that work in practice:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rotation type&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;th&gt;Watch out for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Weekly primary only&lt;/td&gt;
&lt;td&gt;One person holds the pager for 7 days, then hands over&lt;/td&gt;
&lt;td&gt;Teams of 3 to 4 with low page volume&lt;/td&gt;
&lt;td&gt;No backup when the primary is unreachable; burnout if pages are frequent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weekly primary and secondary&lt;/td&gt;
&lt;td&gt;This week's secondary becomes next week's primary&lt;/td&gt;
&lt;td&gt;Most teams of 4 to 10&lt;/td&gt;
&lt;td&gt;Each person holds a pager 2 weeks out of every N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Business hours plus best effort&lt;/td&gt;
&lt;td&gt;Formal paging only during working hours; nights are best effort or limited to SEV1&lt;/td&gt;
&lt;td&gt;Very small teams, B2B products with daytime usage&lt;/td&gt;
&lt;td&gt;Must be agreed with leadership and reflected in customer commitments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weekday and weekend split&lt;/td&gt;
&lt;td&gt;One person covers Monday to Friday, another covers the weekend&lt;/td&gt;
&lt;td&gt;Teams where weekend load is low but non-zero&lt;/td&gt;
&lt;td&gt;Weekend shifts feel heavier; rotate them fairly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow the sun&lt;/td&gt;
&lt;td&gt;Two or three regions each cover their own daytime, 8 to 12 hours each&lt;/td&gt;
&lt;td&gt;Teams spread across time zones with at least 2 to 3 people per region&lt;/td&gt;
&lt;td&gt;Handoff quality between regions becomes the main failure point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service-based rotations&lt;/td&gt;
&lt;td&gt;Each team carries its own pager for the services it owns&lt;/td&gt;
&lt;td&gt;Organizations with several product teams and clear ownership&lt;/td&gt;
&lt;td&gt;Needs a cross-team escalation path for shared infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Default recommendation for a startup: weekly primary and secondary, handover on a weekday morning (never Friday evening or Monday 9 a.m.), with paging limited to customer impact. Move to follow the sun only when you genuinely have people awake in another region.&lt;/p&gt;

&lt;h2&gt;
  
  
  How many engineers you need for a sustainable rotation
&lt;/h2&gt;

&lt;p&gt;Rotation math is simple, and it is the most common thing teams get wrong. With a weekly rotation of N people, each person is primary one week in N. Add a secondary and each person holds a pager 2 weeks in N.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Engineers in rotation&lt;/th&gt;
&lt;th&gt;Primary weeks per year (each)&lt;/th&gt;
&lt;th&gt;Pager weeks per year with secondary (each)&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;Not sustainable for 24/7. Use business hours only.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;about 17&lt;/td&gt;
&lt;td&gt;about 35&lt;/td&gt;
&lt;td&gt;Fragile. One vacation breaks it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;Workable if pages are rare.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;about 9&lt;/td&gt;
&lt;td&gt;about 17&lt;/td&gt;
&lt;td&gt;Comfortable for most startups.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;6.5&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;Healthy for 24/7 from one site.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Google's SRE book gives two reference points that hold up well outside Google: on-call should take no more than 25% of an engineer's time, and a 24/7 rotation from a single site needs at least eight engineers (six per site for a two-site follow-the-sun setup). It also suggests a ceiling of about two incidents per 12-hour shift, because each real incident takes hours once you include the follow-up. See &lt;a href="https://sre.google/sre-book/being-on-call/" rel="noopener noreferrer"&gt;Being On-Call in the Google SRE book&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are below those numbers, that is normal for a startup. Compensate by narrowing what pages (customer impact only), shortening the paging window, and widening the rotation: include every engineer who ships to production, not just the "infra person".&lt;/p&gt;

&lt;h2&gt;
  
  
  Severity levels and paging rules
&lt;/h2&gt;

&lt;p&gt;Paging rules decide whether on-call is tolerable. Agree on severity before the first bad night, then map each level to a response:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Response&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SEV1&lt;/td&gt;
&lt;td&gt;Checkout, login or the core API is down for most users; data loss risk; security incident&lt;/td&gt;
&lt;td&gt;Page primary immediately, 24/7. Escalate to secondary after 5 minutes without acknowledgement.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEV2&lt;/td&gt;
&lt;td&gt;Partial degradation, one region or a subset of customers affected, a critical background job stopped&lt;/td&gt;
&lt;td&gt;Page during the agreed coverage window; otherwise notify the on-call channel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEV3&lt;/td&gt;
&lt;td&gt;Elevated errors below customer impact thresholds, a flaky job, a degraded internal tool&lt;/td&gt;
&lt;td&gt;Ticket for the next working day. Never pages at night.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEV4&lt;/td&gt;
&lt;td&gt;Noisy alert, cleanup, known bug&lt;/td&gt;
&lt;td&gt;Backlog.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 5 minute acknowledgement for user-facing services and around 30 minutes for less time-critical systems match the response targets in the Google SRE book. Pick numbers your team can meet consistently; a promise of 5 minutes that is missed every second weekend is worse than an honest 15.&lt;/p&gt;

&lt;p&gt;Every page should pass three tests: it reflects customer impact or imminent risk of it, the on-call engineer can take a concrete action, and the alert carries enough context to start (service, environment, severity, dashboard link, runbook link, recent deploys). "CPU above 80% for 5 minutes" usually fails all three. "Login error rate above 2% for 5 minutes in production" passes. If your team already ignores alerts, fix that before building the rotation; our guide to &lt;a href="https://meteorops.com/blog/how-to-handle-alert-fatigue" rel="noopener noreferrer"&gt;handling alert fatigue&lt;/a&gt; covers how.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4awxarhz3wylnct17wdh.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4awxarhz3wylnct17wdh.webp" alt="The three tests a page must pass: customer impact or imminent risk, a concrete action for on-call, and enough context to start such as runbook link, dashboard link and recent deploys. CPU above 80% for 5 minutes fails all three; login error rate above 2% for 5 minutes in production passes." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An alert that fails any of the three tests belongs in a ticket or the backlog, not on someone's phone at night.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Escalation policy example
&lt;/h2&gt;

&lt;p&gt;An escalation policy is the ordered list of who gets paged, and when, if nobody acknowledges. Write it down in your paging tool and in the runbook. A good default for a small team:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Escalation policy: production-critical
Level 1: current primary on-call
         page by push + SMS + phone call
         escalate if not acknowledged in 5 minutes
Level 2: current secondary on-call
         escalate if not acknowledged in 10 minutes
Level 3: engineering lead (or CTO)
Repeat:  restart at level 1 up to 2 times

Escalation policy: business-hours
Level 1: current primary on-call, push notification only
         Mon to Fri, 09:00 to 18:00 local time
Outside hours: post to #oncall, create a ticket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also write down when the primary should escalate by choice, not just by timeout: the incident affects paying customers, the failing component is not clear after 15 minutes, a rollback risks data inconsistency, the fix needs access the primary does not have, or the same alert keeps firing after mitigation. Escalating early is a skill, not a failure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffjlvwbik2qxc1jgvavjs.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffjlvwbik2qxc1jgvavjs.webp" alt="Escalation ladder: level 1 primary on-call paged by push, SMS and phone call, level 2 secondary on-call after 5 minutes without acknowledgement, level 3 engineering lead or CTO after 10 more minutes, repeating from level 1 up to 2 times." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Each level only gets paged when the one before it stays silent, so a missed page never ends with nobody responding.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  On-call schedule template
&lt;/h2&gt;

&lt;p&gt;Copy this for a six-person team running weekly primary and secondary, with handover on Wednesday at 10:00. Wednesday handovers keep both people at work for the handoff and avoid starting a shift on a weekend.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Week starting (Wed 10:00)&lt;/th&gt;
&lt;th&gt;Primary&lt;/th&gt;
&lt;th&gt;Secondary&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Week 1&lt;/td&gt;
&lt;td&gt;Engineer A&lt;/td&gt;
&lt;td&gt;Engineer B&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 2&lt;/td&gt;
&lt;td&gt;Engineer B&lt;/td&gt;
&lt;td&gt;Engineer C&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 3&lt;/td&gt;
&lt;td&gt;Engineer C&lt;/td&gt;
&lt;td&gt;Engineer D&lt;/td&gt;
&lt;td&gt;Release freeze, extra care&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 4&lt;/td&gt;
&lt;td&gt;Engineer D&lt;/td&gt;
&lt;td&gt;Engineer E&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 5&lt;/td&gt;
&lt;td&gt;Engineer E&lt;/td&gt;
&lt;td&gt;Engineer F&lt;/td&gt;
&lt;td&gt;Public holiday Thursday: override to Engineer A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 6&lt;/td&gt;
&lt;td&gt;Engineer F&lt;/td&gt;
&lt;td&gt;Engineer A&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rules that keep it fair: swaps are allowed if both people agree and the tool is updated, holidays are distributed across the year, nobody is primary two weeks in a row, and new joiners shadow one full shift as an extra secondary before taking primary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fywmn0vydqo8qnuhew2wl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fywmn0vydqo8qnuhew2wl.webp" alt="Four weeks of a primary and secondary rotation with Wednesday 10:00 handovers: Engineer B is secondary in week 1 and primary in week 2, Engineer C secondary in week 2 and primary in week 3, and so on, so nobody is primary two weeks in a row." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Each engineer spends a week as backup before taking the pager, so they start their primary week already aware of what is going on.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Handoff checklist
&lt;/h3&gt;

&lt;p&gt;A five-minute handoff prevents most "nobody told me" incidents. The outgoing primary posts this in the on-call channel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Incidents and pages from the past shift, and anything still open.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deploys, migrations or config changes that changed production behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Known degraded dependencies, temporary alerts, or silenced monitors (with expiry).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upcoming risky work: launches, load tests, database maintenance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alerts that fired but were not actionable, so they get fixed instead of ignored.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Runbooks and access for the person holding the pager
&lt;/h2&gt;

&lt;p&gt;The on-call engineer should never need to ask "am I allowed to roll this back?" Write runbooks for the incidents you can predict, starting with the top five by frequency: roll back a bad deploy, restart or scale a stuck worker, handle database connection exhaustion, investigate a spike in API errors, rotate a leaked secret. Each runbook needs symptoms, first checks, safe mitigations, risky actions to avoid, and who to call.&lt;/p&gt;

&lt;p&gt;Access is the part teams forget. The primary needs enough access to diagnose and mitigate, but standing admin access for everyone is how incidents get worse. The pattern that works: read access to logs, metrics and cluster state for everyone in the rotation, plus time-limited elevated access (just-in-time roles, or an audited break-glass role) that the on-call engineer can grant themselves during an incident. This also answers a common question: you can remove standing production access from the team without breaking on-call, as long as the elevation path is tested before you need it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdomq0wrpd3ec98vofq6z.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdomq0wrpd3ec98vofq6z.webp" alt="Comparison of on-call access models: standing admin for everyone is how incidents get worse, while the pattern that works combines read access to logs, metrics and cluster state for everyone in the rotation with time-limited elevated access during an incident through a just-in-time role or audited break-glass." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Read access lets anyone diagnose, and elevation is granted only for the incident that needs it.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  On-call compensation and burnout
&lt;/h2&gt;

&lt;p&gt;On-call is work outside normal hours, and teams that treat it as free eventually lose their most reliable engineers. The common compensation models are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flat stipend per shift:&lt;/strong&gt; a fixed amount for each week on primary, regardless of pages. Simple and predictable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Per-incident or hourly pay:&lt;/strong&gt; paid for time actually spent responding outside hours. Fairer when load is uneven, more admin.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Time off in lieu:&lt;/strong&gt; a late-morning start or a day off after a rough night. Cheap and often the most appreciated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Combination:&lt;/strong&gt; a small stipend plus time off after any night page.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Labor rules on standby time vary by country, so check local requirements before you set a policy. Beyond money, the strongest burnout controls are operational: track pages per shift, review every night page in a weekly on-call review, and give the on-call engineer explicit permission to spend quiet shift time fixing the alerts that woke them up.&lt;/p&gt;

&lt;h2&gt;
  
  
  On-call tools: what each is good at
&lt;/h2&gt;

&lt;p&gt;The tool matters less than the policy, but the tool should make schedules, overrides and escalations easy to see and change.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Strength&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PagerDuty&lt;/td&gt;
&lt;td&gt;Mature scheduling, escalation policies and integrations&lt;/td&gt;
&lt;td&gt;The reference product; cost grows with team size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;incident.io&lt;/td&gt;
&lt;td&gt;On-call plus incident workflow inside Slack&lt;/td&gt;
&lt;td&gt;Strong if incidents already run in Slack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grafana Cloud IRM&lt;/td&gt;
&lt;td&gt;On-call and incident response next to Grafana dashboards and alerts&lt;/td&gt;
&lt;td&gt;Natural fit if you already use Grafana&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rootly, FireHydrant&lt;/td&gt;
&lt;td&gt;Incident management with on-call scheduling&lt;/td&gt;
&lt;td&gt;Compare their paging reliability and pricing for your size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opsgenie&lt;/td&gt;
&lt;td&gt;Long-time PagerDuty alternative&lt;/td&gt;
&lt;td&gt;Atlassian ended new sales on June 4, 2025 and shuts it down on April 5, 2027; plan a migration (&lt;a href="https://www.atlassian.com/software/opsgenie/migration" rel="noopener noreferrer"&gt;Atlassian notice&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Whatever you choose, test it: trigger a test page to each person's phone during onboarding, confirm phone-call escalation works with Do Not Disturb on, and review the schedule for gaps every month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common on-call mistakes in small teams
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;One hero on permanent call.&lt;/strong&gt; The person who built the infrastructure answers every page. It feels efficient until they leave or burn out.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Paging on symptoms nobody can act on.&lt;/strong&gt; Resource alerts without user impact train people to ignore the pager.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No secondary.&lt;/strong&gt; A dead phone battery becomes a full outage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Handover on Monday morning.&lt;/strong&gt; The outgoing person is already in planning meetings and the handoff gets skipped.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Runbooks that live in someone's head.&lt;/strong&gt; The first incident handled by a new engineer becomes a guessing game.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No review of pages.&lt;/strong&gt; The same noisy alert wakes someone every week and nothing changes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A 30-day plan to launch on-call before you hire SRE
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Week 1:&lt;/strong&gt; list your production services and name an owner for each. Agree severity levels and the paging window with leadership.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Week 2:&lt;/strong&gt; audit alerts. Delete or downgrade anything that does not pass the three tests. Add the missing customer-impact alerts (error rate, latency, failed critical jobs).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Week 3:&lt;/strong&gt; set up the schedule and escalation policy in your tool, write the top five runbooks, and set up just-in-time elevated access.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Week 4:&lt;/strong&gt; run a game day: trigger a realistic failure in staging and have the primary handle it end to end. Fix what was confusing, then go live.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ll27fcxtu2kv1h47hx8.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ll27fcxtu2kv1h47hx8.webp" alt="Timeline for launching on-call in 30 days: week 1 name service owners and agree severity levels, week 2 audit alerts and add customer-impact alerts, week 3 set up the schedule, escalation policy and top five runbooks, week 4 run a game day in staging and go live, then review pages per shift and time to acknowledge after month one." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Alerts get fixed before the schedule goes live, so the first real shift starts with pages worth answering.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Plan to revisit after the first month: pages per shift, time to acknowledge, and which alerts woke people for nothing. When the rotation itself becomes the bottleneck, that is the signal to formalize the role; our guide on &lt;a href="https://meteorops.com/blog/how-to-build-a-devops-team" rel="noopener noreferrer"&gt;how to build a DevOps team&lt;/a&gt; covers that decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  On-call rotation FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is an on-call rotation?
&lt;/h3&gt;

&lt;p&gt;An on-call rotation is a repeating schedule that assigns one engineer at a time to respond to production alerts, usually for a week. A secondary backs up the primary, and an escalation policy defines who gets paged if nobody acknowledges.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you set up on-call rotations for a small engineering team?
&lt;/h3&gt;

&lt;p&gt;Start with a weekly primary and secondary rotation that includes every engineer who ships to production, page only on customer impact, and hand over midweek with a short written checklist. With fewer than four people, limit formal paging to business hours plus SEV1 at night.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does an on-call schedule work?
&lt;/h3&gt;

&lt;p&gt;The schedule assigns shifts on a calendar, the paging tool routes alerts to whoever is on shift, and overrides cover holidays and swaps. If the primary does not acknowledge within the agreed time, the escalation policy pages the secondary, then a lead.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long should an on-call shift be?
&lt;/h3&gt;

&lt;p&gt;One week is the most common and works well for small teams because it limits handovers. Follow-the-sun teams use 8 to 12 hour shifts per region. Avoid shifts longer than a week unless pages are very rare.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should engineers be paid for on-call?
&lt;/h3&gt;

&lt;p&gt;Most companies compensate on-call through a stipend per shift, pay for time spent on incidents, time off in lieu, or a mix. Unpaid on-call with frequent night pages is one of the fastest ways to lose senior engineers, and local labor rules may require compensation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need an SRE team to run on-call?
&lt;/h3&gt;

&lt;p&gt;No. Product engineers can run a healthy rotation if ownership, alerting, runbooks and escalation are in place. An SRE function becomes worth it when reliability work consistently competes with product work and the rotation is large enough to need dedicated ownership.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many people do you need for 24/7 on-call?
&lt;/h3&gt;

&lt;p&gt;Google's SRE guidance puts the minimum at eight engineers for a single-site 24/7 rotation, or six per site for two sites. Smaller teams can still cover 24/7 by keeping night paging to true emergencies and keeping page volume low.&lt;/p&gt;

&lt;p&gt;If you need production covered before your team is big enough to carry a pager sustainably, MeteorOps provides &lt;a href="https://meteorops.com/services/sre-on-call-support" rel="noopener noreferrer"&gt;SRE on-call support&lt;/a&gt; that plugs into your existing rotation and tooling.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>sre</category>
      <category>management</category>
      <category>startup</category>
    </item>
    <item>
      <title>Kubernetes HPA: How It Works and How to Stop Flapping</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Mon, 02 Nov 2026 07:30:09 +0000</pubDate>
      <link>https://dev.to/meteorops/kubernetes-hpa-how-it-works-and-how-to-stop-flapping-1cmm</link>
      <guid>https://dev.to/meteorops/kubernetes-hpa-how-it-works-and-how-to-stop-flapping-1cmm</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide was written by &lt;a href="https://meteorops.com/team/arthur-azrieli" rel="noopener noreferrer"&gt;Arthur Azrieli&lt;/a&gt;, CTO at MeteorOps, and first published on the &lt;a href="https://meteorops.com/blog/how-to-configure-kubernetes-hpa-without-causing-scaling-flaps" rel="noopener noreferrer"&gt;MeteorOps blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;The Kubernetes Horizontal Pod Autoscaler (HPA) adds or removes pod replicas for a Deployment, StatefulSet or other scalable workload based on a metric such as CPU utilization. Every 15 seconds it compares the current metric to your target, computes &lt;code&gt;ceil(currentReplicas × current / target)&lt;/code&gt;, and scales within your &lt;code&gt;minReplicas&lt;/code&gt; and &lt;code&gt;maxReplicas&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is the whole idea. Most of the trouble comes later, when replica counts start bouncing up and down, targets show &lt;code&gt;&amp;amp;lt;unknown&amp;amp;gt;&lt;/code&gt;, or a GitOps tool keeps resetting the replica count. This guide covers how the algorithm really behaves (including the parts most tutorials skip), copy-paste manifests for the common cases, the &lt;code&gt;behavior&lt;/code&gt; settings that stop scaling flaps, how HPA fits with VPA, KEDA, Karpenter and Argo Rollouts, and a troubleshooting table built from the actual controller error messages.&lt;/p&gt;

&lt;p&gt;Versions referenced: Kubernetes 1.37 (the current release in October 2026), metrics-server v0.9.0 and KEDA v2.21. The &lt;code&gt;autoscaling/v2&lt;/code&gt; API used throughout has been stable since Kubernetes 1.23, so everything here works on any supported cluster unless a section says otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes autoscalers compared: HPA, VPA, KEDA and node autoscalers
&lt;/h2&gt;

&lt;p&gt;"Kubernetes autoscaling" means four different things, and mixing them up causes most bad designs. The HPA only changes the number of pods. It never changes pod size and never adds nodes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Autoscaler&lt;/th&gt;
&lt;th&gt;What it changes&lt;/th&gt;
&lt;th&gt;Typical signal&lt;/th&gt;
&lt;th&gt;Use it when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Horizontal Pod Autoscaler (HPA)&lt;/td&gt;
&lt;td&gt;Replica count of a workload&lt;/td&gt;
&lt;td&gt;CPU or memory utilization, custom or external metrics&lt;/td&gt;
&lt;td&gt;Stateless services where more pods means more capacity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vertical Pod Autoscaler (VPA)&lt;/td&gt;
&lt;td&gt;CPU and memory requests of each pod&lt;/td&gt;
&lt;td&gt;Historical usage&lt;/td&gt;
&lt;td&gt;Right-sizing requests, or workloads that cannot scale out&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KEDA&lt;/td&gt;
&lt;td&gt;Replica count, including to and from zero (it creates and manages an HPA for you)&lt;/td&gt;
&lt;td&gt;Event sources: queue length, Kafka lag, cron, Prometheus queries, cloud services&lt;/td&gt;
&lt;td&gt;Queue consumers and event-driven workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cluster Autoscaler or Karpenter&lt;/td&gt;
&lt;td&gt;Number and type of nodes&lt;/td&gt;
&lt;td&gt;Pending pods that cannot be scheduled&lt;/td&gt;
&lt;td&gt;Always, if the HPA can create more pods than your nodes can hold&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The usual production setup is HPA (or KEDA) for pods plus Cluster Autoscaler or Karpenter for nodes. If the node layer is missing, the HPA happily creates pods that sit in &lt;code&gt;Pending&lt;/code&gt;, and you get the cost of a scale-up decision without the capacity. Our guide on &lt;a href="https://meteorops.com/blog/how-to-set-up-kubernetes-autoscaling-without-creating-cost-surprises" rel="noopener noreferrer"&gt;setting up Kubernetes autoscaling without cost surprises&lt;/a&gt; covers the node side.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Horizontal Pod Autoscaler algorithm works
&lt;/h2&gt;

&lt;p&gt;The HPA is a control loop inside &lt;code&gt;kube-controller-manager&lt;/code&gt;. It does not react to events. It wakes up on an interval (&lt;code&gt;--horizontal-pod-autoscaler-sync-period&lt;/code&gt;, 15 seconds by default), reads metrics, and computes a desired replica count:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;desiredReplicas = ceil( currentReplicas × currentMetricValue / desiredMetricValue )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example: 4 replicas averaging 90% CPU utilization against a 60% target gives &lt;code&gt;ceil(4 × 90 / 60) = ceil(6.0) = 6&lt;/code&gt; replicas. At 45% utilization it gives &lt;code&gt;ceil(4 × 45 / 60) = 3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For resource metrics, "utilization" is usage divided by the container's &lt;strong&gt;request&lt;/strong&gt;, not its limit and not node capacity. A pod requesting 250m CPU and using 200m is at 80%. This single fact explains a large share of HPA surprises: change the request and you change the scaling math, even though nothing about the traffic changed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwkecicmf5fpgsgf16n53.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwkecicmf5fpgsgf16n53.webp" alt="Flow chart of the HPA control loop: every 15 seconds it reads metrics (utilization is usage divided by request), computes ceil(4 x 90 / 60) = 6, does nothing if the ratio is within 10% of target (54% to 66% for a 60% target), and otherwise scales to 6 replicas within minReplicas and maxReplicas." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The HPA recomputes desired replicas on a fixed interval and skips any change that falls inside the 10% tolerance.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The details that shape real behavior
&lt;/h3&gt;

&lt;p&gt;The formula is the easy part. These rules, all from the Kubernetes documentation, decide what actually happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tolerance.&lt;/strong&gt; If the ratio &lt;code&gt;current / target&lt;/code&gt; is within 10% of 1.0, the HPA does nothing. With a 60% CPU target, anything between 54% and 66% is a no-op. This dead band is your first protection against jitter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unready pods are set aside.&lt;/strong&gt; When scaling on CPU, pods that are not yet ready, or whose latest metric sample predates readiness, are excluded from the average. If the result would be a scale up, those pods are then assumed to use 0% of the target, which dampens the scale up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Missing metrics are treated conservatively.&lt;/strong&gt; Pods with no metric are assumed to use 100% of the target when the HPA is considering a scale down, and 0% when considering a scale up. If that reverses the direction or lands inside the tolerance, the HPA skips the action.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Startup windows.&lt;/strong&gt; &lt;code&gt;--horizontal-pod-autoscaler-initial-readiness-delay&lt;/code&gt; (default 30 seconds) and &lt;code&gt;--horizontal-pod-autoscaler-cpu-initialization-period&lt;/code&gt; (default 5 minutes) control how the controller treats CPU samples from freshly started pods. These are control plane flags, so on EKS, GKE or AKS you cannot change them. Design the workload around the defaults instead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiple metrics take the maximum.&lt;/strong&gt; With CPU and a requests-per-second metric, the HPA computes a desired count for each and uses the highest. If one metric cannot be fetched and the others suggest a scale down, the scale down is skipped. Scale up still works.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Status shows the raw value.&lt;/strong&gt; &lt;code&gt;kubectl get hpa&lt;/code&gt; reports the original average, not the adjusted one used for the decision. That is why the TARGETS column can look like it should trigger a scale and nothing happens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scale down is smoothed by default.&lt;/strong&gt; The HPA keeps the highest recommendation from the last 5 minutes before scaling down. That default stabilization window is why replicas linger after a spike.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Prerequisites: metrics-server and resource requests
&lt;/h2&gt;

&lt;p&gt;Resource metrics (CPU and memory) come from the &lt;code&gt;metrics.k8s.io&lt;/code&gt; API, which metrics-server provides. Many managed clusters ship it, many do not. Check first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get apiservice v1beta1.metrics.k8s.io
kubectl top pods -n production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;kubectl top&lt;/code&gt; fails, install metrics-server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then make sure every container in the target pods has a CPU request (and a memory request if you scale on memory). The HPA computes utilization per pod across all its containers, so a single sidecar without a request breaks CPU utilization scaling for the whole workload. If your requests are guesses, fix them before tuning the HPA. Our guide to &lt;a href="https://meteorops.com/blog/how-to-set-kubernetes-resource-requests-and-limits-without-throttling-apps" rel="noopener noreferrer"&gt;Kubernetes requests and limits&lt;/a&gt; shows how to size them from real usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create your first HPA
&lt;/h2&gt;

&lt;p&gt;The fastest way is &lt;code&gt;kubectl autoscale&lt;/code&gt;. Recent kubectl versions use &lt;code&gt;--cpu&lt;/code&gt; with a percentage (the older &lt;code&gt;--cpu-percent&lt;/code&gt; flag is deprecated):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl autoscale deployment api -n production --min=3 --max=20 --cpu=60%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For anything you run in production, keep the HPA in version control as YAML instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch it work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get hpa api -n production --watch
kubectl describe hpa api -n production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;describe&lt;/code&gt; is where the useful information lives: current metrics, the three status conditions (&lt;code&gt;AbleToScale&lt;/code&gt;, &lt;code&gt;ScalingActive&lt;/code&gt;, &lt;code&gt;ScalingLimited&lt;/code&gt;) and recent scaling events with reasons.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove spec.replicas when the HPA owns the count
&lt;/h3&gt;

&lt;p&gt;The Kubernetes docs recommend removing &lt;code&gt;spec.replicas&lt;/code&gt; from the Deployment once an HPA manages it. Otherwise every &lt;code&gt;kubectl apply&lt;/code&gt;, Helm upgrade or Argo CD sync resets the replica count to the value in Git, the HPA scales it back, and you get a sawtooth that looks exactly like flapping. In Helm charts, the common pattern is to render &lt;code&gt;replicas&lt;/code&gt; only when autoscaling is disabled. In Argo CD, you can also add &lt;code&gt;/spec/replicas&lt;/code&gt; to &lt;code&gt;ignoreDifferences&lt;/code&gt; for the Deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  HPA metric types: resource, container, pods, object and external
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;autoscaling/v2&lt;/code&gt; API supports five metric source types. Pick the one that measures the real bottleneck, not the one that is easiest to wire up.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it measures&lt;/th&gt;
&lt;th&gt;Needs&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Resource&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CPU or memory across the whole pod, as utilization or average value&lt;/td&gt;
&lt;td&gt;metrics-server&lt;/td&gt;
&lt;td&gt;CPU-bound web services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ContainerResource&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CPU or memory of one named container&lt;/td&gt;
&lt;td&gt;metrics-server, Kubernetes 1.30 or newer (stable)&lt;/td&gt;
&lt;td&gt;Pods with sidecars (service mesh proxies, log shippers) that distort the pod average&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Pods&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A custom per-pod metric averaged across pods&lt;/td&gt;
&lt;td&gt;A custom metrics adapter such as Prometheus Adapter&lt;/td&gt;
&lt;td&gt;Requests per second or in-flight requests per pod&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Object&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A metric describing another Kubernetes object&lt;/td&gt;
&lt;td&gt;A custom metrics adapter&lt;/td&gt;
&lt;td&gt;Requests per second on an Ingress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;External&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A metric from outside the cluster&lt;/td&gt;
&lt;td&gt;An external metrics adapter (KEDA provides one)&lt;/td&gt;
&lt;td&gt;Queue depth, Pub/Sub backlog, Kafka lag&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Scaling only the application container when a sidecar is present:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;metrics:
  - type: ContainerResource
    containerResource:
      name: cpu
      container: app
      target:
        type: Utilization
        averageUtilization: 60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scaling on a per-pod custom metric (for example, exposed by Prometheus Adapter as &lt;code&gt;http_requests_per_second&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;metrics:
  - type: Pods
    pods:
      metric:
        name: http_requests_per_second
      target:
        type: AverageValue
        averageValue: "50"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few rules of thumb from running these in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU&lt;/strong&gt; is a good signal when traffic turns directly into CPU work: serialization, compression, TLS, rendering.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory&lt;/strong&gt; is a poor scaling signal for most runtimes. The JVM, Go, Node.js and Python rarely give memory back quickly after load drops, so a memory-based HPA scales up easily and then refuses to scale down. Use it only when memory per pod clearly falls as you add pods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requests per second or in-flight requests&lt;/strong&gt; beat CPU for I/O-bound APIs that spend their time waiting on databases or other services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Queue depth or lag&lt;/strong&gt; is the right signal for workers. A worker blocked on a slow dependency shows low CPU while the queue grows, so CPU scaling never fires. Use KEDA here.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why HPAs flap, and how to stop it
&lt;/h2&gt;

&lt;p&gt;Flapping means the replica count oscillates: up on a spike, down a minute later, up again. Users feel it as latency spikes during scale ups, connection churn during scale downs, and a cluster that never settles. The causes are almost always one of these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requests set too low.&lt;/strong&gt; A pod that normally uses 300m with a 100m request sits at 300% utilization at idle. Small traffic changes swing the ratio wildly. Fix the request first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A noisy metric.&lt;/strong&gt; Per-second request rates, garbage collection pauses and batchy traffic produce sharp short peaks. The HPA sees them every 15 seconds and reacts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Startup CPU spikes.&lt;/strong&gt; JIT compilation, cache warm-up and connection pool creation make new pods look overloaded, which triggers more scale up, which starts more pods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scale down that is too fast.&lt;/strong&gt; Removing many pods at once pushes the survivors over the target, and the HPA adds them back.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A target with no headroom.&lt;/strong&gt; A 90% CPU target leaves nothing for the minute or two it takes a new pod to become ready.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Something else is changing replicas.&lt;/strong&gt; A GitOps sync resetting &lt;code&gt;spec.replicas&lt;/code&gt;, two HPAs pointing at the same Deployment, or KEDA and a hand-written HPA on the same target.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Causes 1, 5 and 6 are configuration errors you fix in the workload. Causes 2, 3 and 4 are what the &lt;code&gt;behavior&lt;/code&gt; field exists for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc0qp1n3bidnothge08g2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc0qp1n3bidnothge08g2.webp" alt="Two panels splitting six causes of HPA flapping: fix in the workload (requests set too low, a target with no headroom, something else changing replicas) and tame with the behavior field (a noisy metric, startup CPU spikes, scale down that is too fast)." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Half of flapping is a configuration error in the workload; the other half is what scaling behavior settings are for.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  HPA behavior: stabilization windows and scaling policies
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;behavior&lt;/code&gt; field lets you control scale up and scale down separately. Each direction has a stabilization window, one or more rate-limiting policies, and a &lt;code&gt;selectPolicy&lt;/code&gt; that decides which policy wins. Fields you do not set are merged with these defaults:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;behavior:
  scaleDown:
    stabilizationWindowSeconds: 300
    policies:
      - type: Percent
        value: 100
        periodSeconds: 15
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
      - type: Percent
        value: 100
        periodSeconds: 15
      - type: Pods
        value: 4
        periodSeconds: 15
    selectPolicy: Max
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In words: by default the HPA can double the replica count (or add 4 pods, whichever is more) every 15 seconds with no delay, and can remove every pod above &lt;code&gt;minReplicas&lt;/code&gt; in one step once the 5-minute scale-down window has passed. That is aggressive in both directions.&lt;/p&gt;

&lt;h3&gt;
  
  
  What each field does
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;stabilizationWindowSeconds&lt;/code&gt;&lt;/strong&gt;: the HPA looks at all recommendations made during this window and uses the most conservative one. For scale down that is the highest recommendation, so a brief dip does not remove pods. For scale up it is the lowest, so a brief spike does not add pods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;policies&lt;/code&gt;&lt;/strong&gt;: rate limits. &lt;code&gt;type: Pods, value: 4, periodSeconds: 60&lt;/code&gt; means at most 4 pods per minute. &lt;code&gt;type: Percent, value: 10, periodSeconds: 60&lt;/code&gt; means at most 10% of current replicas per minute (fractions are rounded up, so 10% of 72 replicas allows 8).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;selectPolicy&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;Max&lt;/code&gt; picks the policy allowing the biggest change, &lt;code&gt;Min&lt;/code&gt; the smallest, and &lt;code&gt;Disabled&lt;/code&gt; turns off scaling in that direction entirely.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;tolerance&lt;/code&gt;&lt;/strong&gt; (per direction): overrides the cluster-wide 10% dead band for this HPA. It is beta in Kubernetes 1.35 and 1.36 and generally available from 1.37, so check your cluster version before relying on it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjvhuoanhnjctdbeinopl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjvhuoanhnjctdbeinopl.webp" alt="Two bar charts of recommendations over a stabilization window: for scale down the highest recommendation wins so a brief dip removes no pods, and for scale up the lowest wins so a brief spike adds no pods." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A stabilization window ignores short dips and spikes by acting on the most conservative recent recommendation.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Anti-flap profiles you can copy
&lt;/h3&gt;

&lt;p&gt;Starting points, not final answers. Tune them with the load test in the next section.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workload&lt;/th&gt;
&lt;th&gt;Scale up&lt;/th&gt;
&lt;th&gt;Scale down&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Latency-sensitive API, fast startup (under 30 seconds)&lt;/td&gt;
&lt;td&gt;No window, max of 100% or 4 pods per 60 seconds&lt;/td&gt;
&lt;td&gt;300 second window, 20% per 60 seconds&lt;/td&gt;
&lt;td&gt;React fast to real load, shed capacity slowly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slow-starting service (JVM, large caches)&lt;/td&gt;
&lt;td&gt;60 second window, 50% per 60 seconds&lt;/td&gt;
&lt;td&gt;600 second window, 10% per 60 seconds&lt;/td&gt;
&lt;td&gt;Stop startup spikes from compounding; keep warm pods&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spiky, bursty traffic&lt;/td&gt;
&lt;td&gt;No window, 100% per 30 seconds&lt;/td&gt;
&lt;td&gt;900 second window, 1 pod per 120 seconds&lt;/td&gt;
&lt;td&gt;Bursts return; keeping capacity is cheaper than churn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Batch or queue worker on CPU&lt;/td&gt;
&lt;td&gt;No window, 4 pods per 60 seconds&lt;/td&gt;
&lt;td&gt;300 second window, 25% per 60 seconds&lt;/td&gt;
&lt;td&gt;Usually better on KEDA with queue depth&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The latency-sensitive API profile as YAML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 3
  maxReplicas: 30
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 0
      selectPolicy: Max
      policies:
        - type: Percent
          value: 100
          periodSeconds: 60
        - type: Pods
          value: 4
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300
      selectPolicy: Min
      policies:
        - type: Percent
          value: 20
          periodSeconds: 60
        - type: Pods
          value: 2
          periodSeconds: 60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;selectPolicy: Min&lt;/code&gt; on scale down, the HPA removes whichever is smaller, 20% or 2 pods, per minute. At 30 replicas that is 2 pods a minute, so once the 5-minute window has passed it takes about 13 more minutes to return to 3. That is deliberate: slow scale down is the cheapest insurance against flapping.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foz74aqv46k6xc60vs7qn.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foz74aqv46k6xc60vs7qn.webp" alt="Line chart of replicas after load drops: the count holds at 30 during the 300 second window, then steps down 2 pods per minute for about 13 minutes until it reaches 3, because selectPolicy Min picks 2 pods over 20%." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Holding capacity for five minutes and then shedding 2 pods a minute is cheap insurance against flapping.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  How to pick the target utilization
&lt;/h3&gt;

&lt;p&gt;The target is really a headroom setting. Ask how much traffic can grow in the time it takes a new pod to become ready and serve. If traffic can rise 50% in the two minutes it takes to start a pod, existing pods need room to absorb that, so a target near 100 / 1.5, about 65% of the point where latency degrades, is the ceiling. If your service degrades at 80% CPU, that gives roughly 50% to 55%.&lt;/p&gt;

&lt;p&gt;Most CPU-bound services land between 50% and 70%. Below 50% you pay for a lot of idle capacity. Above 75% you are betting that scale ups always finish before the next spike.&lt;/p&gt;
&lt;h2&gt;
  
  
  Test HPA behavior before production traffic does
&lt;/h2&gt;

&lt;p&gt;Do not trust an HPA you have not watched under load. In a staging environment with realistic requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# terminal 1: decisions and events
kubectl get hpa api -n staging --watch
kubectl get events -n staging --field-selector involvedObject.name=api --watch

# terminal 2: pods coming and going
kubectl get pods -n staging -l app=api --watch

# terminal 3: load from outside the cluster for 10 minutes, then stop
hey -z 10m -c 100 https://staging.example.com/api/health-heavy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Record five things: time to first scale up, replicas added per minute, whether new pods were ready before the next decision, whether latency recovered, and how replicas stepped down after the load stopped. If replicas climb past what the load needs, your scale up is outrunning readiness. If they drop and come straight back, slow the scale down.&lt;/p&gt;

&lt;h2&gt;
  
  
  HPA with VPA, KEDA, Karpenter and Argo Rollouts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  HPA and VPA
&lt;/h3&gt;

&lt;p&gt;Do not let both act on the same resource metric. If the HPA scales on CPU utilization and VPA raises CPU requests, utilization drops, the HPA removes pods, utilization rises, and the two loops chase each other. Safe combinations are VPA in recommendation-only mode (&lt;code&gt;updateMode: "Off"&lt;/code&gt;) to inform your requests, or HPA on a custom metric such as requests per second while VPA manages CPU and memory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpftklrrboibgh43vm9pb.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpftklrrboibgh43vm9pb.webp" alt="Loop diagram: VPA raises CPU requests, utilization drops, the HPA removes pods, utilization rises, and the cycle repeats. Safe combinations: VPA in recommendation mode with updateMode Off, or HPA on requests per second with VPA on CPU and memory." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Give the HPA and VPA different signals, or keep VPA in recommendation mode, so they never fight over one metric.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  HPA and KEDA
&lt;/h3&gt;

&lt;p&gt;KEDA is not a competitor to the HPA. A KEDA &lt;code&gt;ScaledObject&lt;/code&gt; creates and manages an HPA for you and feeds it external metrics from its 70+ built-in scalers, plus it handles activation from zero replicas. Never point your own HPA and a KEDA ScaledObject at the same Deployment. Choose KEDA when the signal lives outside the pod (queues, streams, schedules) or when you need scale to zero.&lt;/p&gt;

&lt;h3&gt;
  
  
  HPA and node autoscaling
&lt;/h3&gt;

&lt;p&gt;When the HPA adds pods that do not fit, they stay &lt;code&gt;Pending&lt;/code&gt; until Cluster Autoscaler or Karpenter adds a node, which commonly takes one to several minutes. Your scale-up speed is therefore the slower of pod startup and node provisioning. If that is too slow for your traffic pattern, raise &lt;code&gt;minReplicas&lt;/code&gt;, lower the target, or keep a little spare node capacity with low-priority placeholder pods that real workloads can preempt (see our guide to &lt;a href="https://meteorops.com/blog/how-to-configure-kubernetes-priorityclasses-without-starving-workloads" rel="noopener noreferrer"&gt;Kubernetes PriorityClasses&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  HPA during rollouts
&lt;/h3&gt;

&lt;p&gt;During a rolling update the HPA scales the Deployment, and the Deployment controller spreads replicas across old and new ReplicaSets. Startup CPU from new pods can trigger scale ups mid-rollout, so the slow-starting profile above helps here too. If you use progressive delivery, point &lt;code&gt;scaleTargetRef&lt;/code&gt; at the Rollout instead of a Deployment (&lt;code&gt;apiVersion: argoproj.io/v1alpha1&lt;/code&gt;, &lt;code&gt;kind: Rollout&lt;/code&gt;). Our &lt;a href="https://meteorops.com/blog/how-to-deploy-zero-downtime-kubernetes-releases-with-helm-and-argo-rollouts" rel="noopener noreferrer"&gt;Argo Rollouts guide&lt;/a&gt; covers how canary and blue-green steps interact with the HPA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can the HPA scale to zero?
&lt;/h2&gt;

&lt;p&gt;Only for object and external metrics, and only with the &lt;code&gt;HPAScaleToZero&lt;/code&gt; feature gate. That gate was alpha (off by default) from Kubernetes 1.16 to 1.36 and became beta, on by default, in 1.37. CPU and memory cannot scale to zero because they can only be measured on running pods. On older clusters, or for anything event driven, use KEDA, which has supported scale to zero for years.&lt;/p&gt;

&lt;h2&gt;
  
  
  HPA troubleshooting: error messages and fixes
&lt;/h2&gt;

&lt;p&gt;These are the messages the HPA controller actually emits, as seen in &lt;code&gt;kubectl describe hpa&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom or message&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TARGETS shows &lt;code&gt;&amp;amp;lt;unknown&amp;amp;gt;/60%&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;No metrics yet, metrics-server missing, or a container without a request&lt;/td&gt;
&lt;td&gt;Wait one or two minutes after creation; run &lt;code&gt;kubectl top pods&lt;/code&gt;; add requests to every container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;failed to get cpu utilization: missing request for cpu in container X of Pod Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A container (often a sidecar or init-injected proxy) has no CPU request&lt;/td&gt;
&lt;td&gt;Add a CPU request to every container, or switch to &lt;code&gt;ContainerResource&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;unable to get metrics for resource cpu: ...&lt;/code&gt; with reason &lt;code&gt;FailedGetResourceMetric&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;metrics.k8s.io&lt;/code&gt; API is unavailable&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;kubectl get apiservice v1beta1.metrics.k8s.io&lt;/code&gt; and the metrics-server pod logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;did not receive metrics for targeted pods (pods might be unready)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pods are crash looping or never become ready&lt;/td&gt;
&lt;td&gt;Fix readiness first; see our guide to &lt;a href="https://meteorops.com/blog/how-to-configure-kubernetes-liveness-probes-without-causing-restart-loops" rel="noopener noreferrer"&gt;liveness probes without restart loops&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ScalingLimited True TooManyReplicas&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The desired count hit &lt;code&gt;maxReplicas&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;maxReplicas&lt;/code&gt; only if downstream systems (database, cache, APIs) can take it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;ScaleDownStabilized&lt;/code&gt; while load is low&lt;/td&gt;
&lt;td&gt;The scale-down window is holding the highest recent recommendation&lt;/td&gt;
&lt;td&gt;Expected. Shorten the window only if idle cost matters more than churn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replicas jump back to a fixed number after every deploy&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;spec.replicas&lt;/code&gt; in the manifest overrides the HPA on each apply or sync&lt;/td&gt;
&lt;td&gt;Remove &lt;code&gt;spec.replicas&lt;/code&gt;, or ignore it in Argo CD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory HPA never scales down&lt;/td&gt;
&lt;td&gt;The runtime keeps memory after load drops&lt;/td&gt;
&lt;td&gt;Scale on CPU or a work metric instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;More pods, same latency&lt;/td&gt;
&lt;td&gt;The bottleneck is a database, lock or external API&lt;/td&gt;
&lt;td&gt;Cap &lt;code&gt;maxReplicas&lt;/code&gt; at downstream capacity, add pooling and backpressure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Production HPA checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Every container in the target has a CPU request based on measured usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;spec.replicas&lt;/code&gt; is removed from the Deployment manifest, or ignored by your GitOps tool.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;minReplicas&lt;/code&gt; is at least 2 (3 for multi-zone services) and covers normal traffic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;maxReplicas&lt;/code&gt; is set from downstream capacity and node budget, not from a round number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The metric matches the bottleneck: CPU for compute, requests per pod for I/O-bound APIs, queue depth (via KEDA) for workers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scale up is faster than scale down, and scale down has a window of at least 300 seconds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Readiness probes reflect real readiness, and startup time is known.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A node autoscaler is in place and its provisioning time is part of your scale-up budget.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;VPA is not changing the same resource the HPA scales on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You have watched the HPA through a load test and a scale down.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Kubernetes HPA FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is HPA useful for Kubernetes?
&lt;/h3&gt;

&lt;p&gt;Yes, for stateless workloads where more pods means more capacity. It lets you run fewer replicas at quiet times and absorb peaks without manual intervention. It is the wrong tool for stateful systems that cannot simply add replicas, and for workloads whose bottleneck is outside the pod.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a good HPA CPU threshold?
&lt;/h3&gt;

&lt;p&gt;Most CPU-bound services work well between 50% and 70% of the CPU request. Use the headroom calculation above: the slower your pods and nodes start, and the faster your traffic grows, the lower the target should be.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between HPA and VPA?
&lt;/h3&gt;

&lt;p&gt;The HPA changes how many pods run. VPA changes how much CPU and memory each pod requests. They can work together if they act on different signals, for example HPA on requests per second and VPA on resources, or VPA in recommendation mode only.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between KEDA and HPA?
&lt;/h3&gt;

&lt;p&gt;KEDA builds on the HPA. It creates an HPA for you, feeds it metrics from event sources like queues and streams, and adds scale to zero. Use plain HPA for CPU or custom metrics on services; use KEDA for event-driven workers.&lt;/p&gt;

&lt;h3&gt;
  
  
  How often does the HPA check metrics?
&lt;/h3&gt;

&lt;p&gt;Every 15 seconds by default. Metrics-server itself scrapes kubelets on its own interval, so the data the HPA sees can be somewhat older than that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does my HPA show unknown targets?
&lt;/h3&gt;

&lt;p&gt;Either metrics are not available yet (normal for a minute or two after creation), metrics-server is missing or broken, or at least one container in the pods has no request for the resource you scale on. &lt;code&gt;kubectl describe hpa&lt;/code&gt; shows which one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is my HPA not scaling down?
&lt;/h3&gt;

&lt;p&gt;The 5-minute default scale-down stabilization window, a metric still above the target minus the 10% tolerance, a memory metric that never drops, or a second metric that keeps the maximum recommendation high. Check the conditions and events in &lt;code&gt;kubectl describe hpa&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use HPA and a fixed replica count in Helm?
&lt;/h3&gt;

&lt;p&gt;Not on the same object. Render &lt;code&gt;replicas&lt;/code&gt; in the Deployment only when autoscaling is disabled, so a Helm upgrade does not reset the HPA's decision.&lt;/p&gt;

&lt;p&gt;If your autoscaling still behaves unpredictably after this, the cause is usually in the workload or the node layer rather than the HPA itself. MeteorOps engineers tune this for startups as part of &lt;a href="https://meteorops.com/technologies/kubernetes" rel="noopener noreferrer"&gt;Kubernetes consulting&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>performance</category>
      <category>sre</category>
    </item>
    <item>
      <title>SRE vs DevOps: Key Differences and Which Your Startup Needs</title>
      <dc:creator>Michael Zion</dc:creator>
      <pubDate>Sun, 01 Nov 2026 07:30:04 +0000</pubDate>
      <link>https://dev.to/meteorops/sre-vs-devops-key-differences-and-which-your-startup-needs-58ec</link>
      <guid>https://dev.to/meteorops/sre-vs-devops-key-differences-and-which-your-startup-needs-58ec</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide was written by &lt;a href="https://meteorops.com/team/michael-zion" rel="noopener noreferrer"&gt;Michael Zion&lt;/a&gt;, CEO at MeteorOps, and first published on the &lt;a href="https://meteorops.com/blog/sre-vs-devops" rel="noopener noreferrer"&gt;MeteorOps blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SRE vs DevOps in one paragraph:&lt;/strong&gt; DevOps is a culture and set of practices for shipping software faster by removing the wall between development and operations. Site reliability engineering (SRE) is a specific, opinionated way to run production that came out of Google: it sets reliability targets (SLOs), spends an error budget against them, and treats operations as a software problem. Google sums it up as "class SRE implements interface DevOps". DevOps optimizes the path to production. SRE optimizes what happens once you are there.&lt;/p&gt;

&lt;p&gt;Below is how the two differ in goals, daily work, metrics, skills and pay, how they fit together, and which one a startup actually needs at each stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRE vs DevOps at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;DevOps&lt;/th&gt;
&lt;th&gt;SRE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What it is&lt;/td&gt;
&lt;td&gt;A culture and set of practices across the whole delivery lifecycle&lt;/td&gt;
&lt;td&gt;A job role and an engineering discipline for running production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Origin&lt;/td&gt;
&lt;td&gt;A movement among practitioners at many companies, around 2009&lt;/td&gt;
&lt;td&gt;Google, from 2003, written up in the &lt;a href="https://sre.google/sre-book/table-of-contents/" rel="noopener noreferrer"&gt;Site Reliability Engineering&lt;/a&gt; book (2016)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Main question&lt;/td&gt;
&lt;td&gt;How do we ship changes faster and safer?&lt;/td&gt;
&lt;td&gt;How reliable must this service be, and are we meeting that?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core practices&lt;/td&gt;
&lt;td&gt;CI/CD, infrastructure as code, automation, shared ownership, fast feedback&lt;/td&gt;
&lt;td&gt;SLIs and SLOs, error budgets, toil reduction, incident response, blameless postmortems, capacity planning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical metrics&lt;/td&gt;
&lt;td&gt;The five &lt;a href="https://dora.dev/guides/dora-metrics/" rel="noopener noreferrer"&gt;DORA metrics&lt;/a&gt;: change lead time, deployment frequency, failed deployment recovery time, change fail rate, deployment rework rate&lt;/td&gt;
&lt;td&gt;SLO attainment, error budget burn rate, toil percentage, incident count and duration, pages per shift&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prescriptiveness&lt;/td&gt;
&lt;td&gt;Principles; little detail on how to run services&lt;/td&gt;
&lt;td&gt;Concrete rules, such as caps on toil and on-call time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where the work sits&lt;/td&gt;
&lt;td&gt;Pipelines, environments, platforms, developer workflow&lt;/td&gt;
&lt;td&gt;Production systems, observability, on-call, reliability of user-facing services&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1hfeaii3w1j7hh0bixxj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1hfeaii3w1j7hh0bixxj.webp" alt="Diagram of a flow from Commit to CI/CD to Production: DevOps covers the path to production (pipelines, environments, platforms), while SRE covers production once you are there (observability, on-call, reliability)." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;DevOps owns how changes reach production; SRE owns how production behaves once they land.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What DevOps actually means
&lt;/h2&gt;

&lt;p&gt;DevOps started as a reaction to a familiar split: developers were measured on shipping features, operations on keeping things stable, and every release became a fight. DevOps says one team should own the whole path from commit to production, with automation doing the repetitive work.&lt;/p&gt;

&lt;p&gt;A common way to describe it is &lt;strong&gt;CALMS&lt;/strong&gt;: Culture, Automation, Lean, Measurement and Sharing. In practice that means CI/CD pipelines, infrastructure as code, small and frequent changes, environments anyone can recreate, and developers who can see and act on how their code behaves in production.&lt;/p&gt;

&lt;p&gt;"DevOps engineer" is the job title that grew out of this. In most companies a DevOps engineer builds and runs the delivery platform: cloud infrastructure, CI/CD, containers and Kubernetes, secrets, and the tooling that lets developers ship on their own.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SRE actually means
&lt;/h2&gt;

&lt;p&gt;SRE is what you get when you ask software engineers to run operations. Its central idea is that 100% reliability is the wrong target. Users cannot tell 99.99% from 100%, and chasing the last fraction slows every release. So SRE makes reliability an explicit, measured number:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SLI (service level indicator):&lt;/strong&gt; what you measure, such as the share of requests that succeed in under 300 ms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SLO (service level objective):&lt;/strong&gt; the target for that indicator over a window, such as 99.9% over 30 days.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error budget:&lt;/strong&gt; the failure you are allowed. A 99.9% SLO over 30 days allows about 43 minutes of full downtime, or the equivalent in failed requests.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While budget remains, teams ship freely. When it runs out, the priority shifts to reliability work until the service is healthy again. That one rule turns the old dev vs ops argument into a shared, data-driven decision.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg74bkccyc4379sssjlub.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg74bkccyc4379sssjlub.webp" alt="Flow from SLI (what you measure) to SLO (99.9% over 30 days) to an error budget of about 43 minutes, which splits into two outcomes: budget remains, ship freely; budget runs out, reliability work first." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The error budget turns a reliability target into a clear rule for when to ship and when to fix.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;SRE also sets hard limits on operational load. Google's SRE teams aim to keep toil, the manual, repetitive, automatable work that "scales linearly as a service grows", &lt;a href="https://sre.google/sre-book/eliminating-toil/" rel="noopener noreferrer"&gt;below 50% of each engineer's time&lt;/a&gt;. Of the remaining operational time, &lt;a href="https://sre.google/sre-book/being-on-call/" rel="noopener noreferrer"&gt;no more than 25% should be on-call&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much downtime does each SLO allow?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SLO&lt;/th&gt;
&lt;th&gt;Allowed downtime per 30 days&lt;/th&gt;
&lt;th&gt;Per year&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;99%&lt;/td&gt;
&lt;td&gt;7 hours 12 minutes&lt;/td&gt;
&lt;td&gt;about 3.65 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.5%&lt;/td&gt;
&lt;td&gt;3 hours 36 minutes&lt;/td&gt;
&lt;td&gt;about 1.8 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.9%&lt;/td&gt;
&lt;td&gt;43.2 minutes&lt;/td&gt;
&lt;td&gt;about 8.8 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.95%&lt;/td&gt;
&lt;td&gt;21.6 minutes&lt;/td&gt;
&lt;td&gt;about 4.4 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.99%&lt;/td&gt;
&lt;td&gt;4.3 minutes&lt;/td&gt;
&lt;td&gt;about 53 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  "class SRE implements interface DevOps"
&lt;/h2&gt;

&lt;p&gt;Google's own &lt;a href="https://sre.google/workbook/how-sre-relates/" rel="noopener noreferrer"&gt;SRE workbook&lt;/a&gt; frames the relationship this way. DevOps is the interface: a set of principles. SRE is one concrete implementation of those principles, with specific practices for each of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduce organizational silos:&lt;/strong&gt; SREs share ownership of production with developers and use the same tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Accept failure as normal:&lt;/strong&gt; error budgets and blameless postmortems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implement gradual change:&lt;/strong&gt; small changes, canary releases, fast rollback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tooling and culture are interrelated:&lt;/strong&gt; SREs use the same tools as developers, and the toil cap forces automation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Measure everything:&lt;/strong&gt; SLOs and error budgets drive decisions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2o4p9qxv8h6fzaqdfy9z.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2o4p9qxv8h6fzaqdfy9z.webp" alt="Mapping of five DevOps principles to SRE practices: reduce organizational silos to shared ownership of production; accept failure as normal to error budgets and blameless postmortems; implement gradual change to canary releases and fast rollback; tooling and culture are interrelated to a toil cap that forces automation; measure everything to SLOs and error budgets driving decisions." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Each DevOps principle has a concrete SRE practice behind it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The workbook also names the differences: DevOps is broader and targets silos across the whole organization, while SRE is narrower, more prescriptive, and focused on services and their users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Responsibilities side by side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;DevOps engineer&lt;/th&gt;
&lt;th&gt;Site reliability engineer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD&lt;/td&gt;
&lt;td&gt;Builds and owns pipelines, build caching, release automation&lt;/td&gt;
&lt;td&gt;Adds safety: canaries, automated rollback, release gates tied to SLOs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure&lt;/td&gt;
&lt;td&gt;Provisions cloud, networks, clusters with Terraform or similar&lt;/td&gt;
&lt;td&gt;Capacity planning, load testing, failure-mode design, disaster recovery drills&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;Installs and maintains the monitoring and logging stack&lt;/td&gt;
&lt;td&gt;Defines SLIs and SLOs, alerting on symptoms and burn rate, dashboards for incidents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incidents&lt;/td&gt;
&lt;td&gt;Often on the rotation, fixes infrastructure causes&lt;/td&gt;
&lt;td&gt;Leads incident response, runs postmortems, tracks follow-ups to completion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer experience&lt;/td&gt;
&lt;td&gt;Self-service environments, templates, internal platform&lt;/td&gt;
&lt;td&gt;Production readiness reviews, reliability guidance for service owners&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code&lt;/td&gt;
&lt;td&gt;Infrastructure code, scripts, pipeline config&lt;/td&gt;
&lt;td&gt;Automation and tooling, sometimes changes to application code for reliability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In small companies these roles overlap heavily, and one senior engineer often does both. The split becomes real once you have enough services and traffic that reliability needs a dedicated owner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skills: where they overlap and where they don't
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Shared core:&lt;/strong&gt; Linux, networking, a major cloud provider, containers and Kubernetes, infrastructure as code, CI/CD, a scripting or programming language, and monitoring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leans DevOps:&lt;/strong&gt; pipeline design, build systems, Terraform module design, developer tooling, platform engineering, cost-aware infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leans SRE:&lt;/strong&gt; distributed systems failure modes, SLO design, statistics for latency and error rates, performance and capacity analysis, incident command, writing production-grade software in Go, Python or Java.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRE vs DevOps salary
&lt;/h2&gt;

&lt;p&gt;The two pay similarly, with SRE slightly ahead in most surveys. In the &lt;a href="https://survey.stackoverflow.co/2024/work" rel="noopener noreferrer"&gt;2024 Stack Overflow Developer Survey&lt;/a&gt;, median yearly salaries were:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;United States median&lt;/th&gt;
&lt;th&gt;Global median&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SRE&lt;/td&gt;
&lt;td&gt;$166,500&lt;/td&gt;
&lt;td&gt;$99,099&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DevOps specialist&lt;/td&gt;
&lt;td&gt;$145,000&lt;/td&gt;
&lt;td&gt;$72,611&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud infrastructure engineer&lt;/td&gt;
&lt;td&gt;$165,000&lt;/td&gt;
&lt;td&gt;$96,666&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://survey.stackoverflow.co/2025/work" rel="noopener noreferrer"&gt;2025 survey&lt;/a&gt; no longer breaks out SRE, but reports a US median of $165,000 for "DevOps engineer or professional". Seniority, location and company size move pay far more than the title does. Treat the gap between the two roles as small.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which does your startup need?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;What you need&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pre-product or MVP, 1 to 10 engineers&lt;/td&gt;
&lt;td&gt;DevOps practices, owned by developers, with outside help for the foundation&lt;/td&gt;
&lt;td&gt;You need CI/CD, infrastructure as code and basic monitoring. Reliability targets would be guesses.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Early customers, 10 to 30 engineers&lt;/td&gt;
&lt;td&gt;A first DevOps or platform engineer, plus simple SLOs on your one or two critical user journeys&lt;/td&gt;
&lt;td&gt;Delivery speed is the bottleneck. A light SLO keeps reliability from being argued by gut feel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Growth, 30 to 100 engineers&lt;/td&gt;
&lt;td&gt;A platform team and your first SRE, or SRE practices embedded in the platform team&lt;/td&gt;
&lt;td&gt;Incidents, on-call load and enterprise customers' uptime expectations make reliability a full-time job.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale, 100+ engineers or strict SLAs&lt;/td&gt;
&lt;td&gt;A dedicated SRE function alongside platform engineering&lt;/td&gt;
&lt;td&gt;Error budgets, capacity planning and incident management across many teams need clear ownership.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two practical rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hire for the bottleneck.&lt;/strong&gt; If releases are slow and painful, you need DevOps capability. If releases are fine but outages, pages and customer complaints are the problem, you need SRE capability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don't build a 24/7 rotation too early.&lt;/strong&gt; Google's guidance puts the minimum for a single-site 24/7 rotation at eight engineers. Most startups get further with business-hours paging, good runbooks and clear severity rules. Our guide to &lt;a href="https://meteorops.com/blog/how-to-design-on-call-before-you-hire-sre" rel="noopener noreferrer"&gt;designing an on-call rotation for a small team&lt;/a&gt; covers the math.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu7padyhi4ood9i6hls62.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu7padyhi4ood9i6hls62.webp" alt="Decision tree: if releases are slow and painful, you need DevOps capability; if releases are fine but outages and pages are the problem, you need SRE capability." width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Let the problem you feel most decide which capability to hire first.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How DevOps and SRE work together
&lt;/h2&gt;

&lt;p&gt;In a healthy setup, the platform or DevOps team builds the paved road (pipelines, environments, infrastructure modules), and SRE makes sure what runs on that road meets its reliability targets. Concretely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Product teams own their services and their SLOs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The platform team makes the right thing the easy thing: standard deploys, built-in metrics, safe rollbacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SREs set the SLO framework, review production readiness, lead major incidents and push systemic fixes back into the platform.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Error budget policy decides, in advance, what happens when a service runs out of budget.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A practical first step for any team is cleaning up alerting so that pages map to user impact. Our article on &lt;a href="https://meteorops.com/blog/how-to-handle-alert-fatigue" rel="noopener noreferrer"&gt;handling alert fatigue&lt;/a&gt; shows how, and the &lt;a href="https://meteorops.com/blog/how-to-build-a-startup-observability-stack" rel="noopener noreferrer"&gt;observability stack guide&lt;/a&gt; covers what to run at each team size.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Renaming the ops team "SRE".&lt;/strong&gt; Without SLOs, error budgets and a toil cap, it is the same ops team with a new title.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hiring a "DevOps engineer" to be the only person who can deploy.&lt;/strong&gt; That rebuilds the silo DevOps was meant to remove.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setting SLOs at 99.99% by default.&lt;/strong&gt; Each extra nine costs a lot. Start from what users notice and what your dependencies can deliver.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Measuring only uptime.&lt;/strong&gt; Latency and correctness matter to users as much as availability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Treating it as either/or.&lt;/strong&gt; Most teams need DevOps practices first and SRE practices as they grow, not one instead of the other.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is SRE better than DevOps?
&lt;/h3&gt;

&lt;p&gt;Neither is better; they solve different problems. DevOps improves how you build and ship software. SRE improves how reliably it runs. SRE is often described as one specific implementation of DevOps principles, so a mature organization usually uses both.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is DevOps a part of SRE, or SRE a part of DevOps?
&lt;/h3&gt;

&lt;p&gt;SRE is generally seen as an implementation of DevOps. Google's phrase is "class SRE implements interface DevOps": DevOps defines the principles, and SRE is a concrete, prescriptive way to apply them to running production services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who earns more, SRE or DevOps?
&lt;/h3&gt;

&lt;p&gt;SREs usually earn slightly more. In the 2024 Stack Overflow Developer Survey, the US median was $166,500 for SREs and $145,000 for DevOps specialists. Seniority, location and employer matter more than the title.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can a DevOps engineer become an SRE?
&lt;/h3&gt;

&lt;p&gt;Yes, it is one of the most common paths. Add stronger programming skills, learn SLO and error budget design, get comfortable leading incidents and postmortems, and go deeper on distributed systems failure modes and capacity planning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Will AI replace SRE jobs?
&lt;/h3&gt;

&lt;p&gt;AI tools are taking over parts of the work, such as summarizing incidents, correlating alerts and drafting runbooks and postmortems. The judgment parts remain: choosing reliability targets, deciding trade-offs during incidents and designing systems that fail safely. The role is shifting toward that work, not disappearing.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between SRE and platform engineering?
&lt;/h3&gt;

&lt;p&gt;Platform engineering builds the internal products developers use to ship: templates, pipelines, environments, an internal developer platform. SRE focuses on the reliability of the services running in production. Many startups combine them in one team until they grow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does a startup need an SRE?
&lt;/h3&gt;

&lt;p&gt;Usually not as a first infrastructure hire. Most startups need DevOps capability first, with simple SLOs on critical user journeys. A dedicated SRE starts to pay off when incidents, on-call load or customer uptime commitments take a meaningful share of engineering time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short answer
&lt;/h2&gt;

&lt;p&gt;DevOps gets your changes to production quickly and safely. SRE keeps production as reliable as your users need, and no more. Start with DevOps practices, add SLOs early and cheaply, and bring in dedicated SRE when reliability becomes a job of its own.&lt;/p&gt;

&lt;p&gt;Need senior help with either? MeteorOps provides &lt;a href="https://meteorops.com/services/devops-consulting" rel="noopener noreferrer"&gt;DevOps consulting&lt;/a&gt; and &lt;a href="https://meteorops.com/services/sre-on-call-support" rel="noopener noreferrer"&gt;SRE and on-call support&lt;/a&gt; for startups, from first pipelines to SLOs and incident response.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>sre</category>
      <category>startup</category>
      <category>management</category>
    </item>
  </channel>
</rss>
