<?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: DevOps Daily</title>
    <description>The latest articles on DEV Community by DevOps Daily (@devopsdaily).</description>
    <link>https://dev.to/devopsdaily</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%2Fuser%2Fprofile_image%2F382434%2F3b4f7f10-38d4-4f4f-8351-1dcb0c1bdfc7.png</url>
      <title>DEV Community: DevOps Daily</title>
      <link>https://dev.to/devopsdaily</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devopsdaily"/>
    <language>en</language>
    <item>
      <title>Neon Is Becoming a Backend Platform, Not Just Postgres</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Wed, 01 Jul 2026 15:30:52 +0000</pubDate>
      <link>https://dev.to/devopsdaily/neon-is-becoming-a-backend-platform-not-just-postgres-2c26</link>
      <guid>https://dev.to/devopsdaily/neon-is-becoming-a-backend-platform-not-just-postgres-2c26</guid>
      <description>&lt;p&gt;For most of its life, Neon had a one-sentence pitch: serverless Postgres that branches like Git. You got a database that scaled to zero, forked in milliseconds, and charged you for what you used. Everything else (your compute, your file storage, your AI calls, your auth) you wired up somewhere else and pointed at the connection string.&lt;/p&gt;

&lt;p&gt;In June 2026 that sentence got longer. Neon shipped a private preview that adds three new surfaces around the database: serverless &lt;strong&gt;Functions&lt;/strong&gt;, S3-compatible &lt;strong&gt;Storage&lt;/strong&gt;, and an &lt;strong&gt;AI Gateway&lt;/strong&gt; for model calls. A fourth, &lt;strong&gt;Neon Auth&lt;/strong&gt;, shows up in the templates. None of these is novel on its own. Functions look like Lambda, storage looks like S3, an AI gateway looks like a dozen other AI gateways. The reason it is worth a closer look is the through-line connecting them, and that through-line is the same primitive Neon already built its name on: branching.&lt;/p&gt;

&lt;p&gt;This is an analysis of what actually shipped, what it replaces, and where it is still clearly a preview. I created a new project and deployed against it while writing this, so the specifics below are from the real thing, not the marketing page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What shipped
&lt;/h2&gt;

&lt;p&gt;Four pieces, all in private preview, all in AWS &lt;code&gt;us-east-2&lt;/code&gt;, all for new projects only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Neon Functions&lt;/strong&gt; are Node.js compute deployed onto a database branch. You declare them in a &lt;code&gt;neon.ts&lt;/code&gt; config file, write a standard Fetch-API handler (Hono is the recommended framework), and run &lt;code&gt;neonctl deploy&lt;/code&gt;. Each branch gets its own function URL, the &lt;code&gt;DATABASE_URL&lt;/code&gt; is injected automatically, and the function runs in the same region as the branch, so there is no cross-region hop to the database. They support streaming and long-lived connections (WebSockets, server-sent events), which is the deliberate split from request-scoped serverless: these are not for background jobs, they are for request/response and real-time work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Neon Storage&lt;/strong&gt; is S3-compatible object storage. Your existing AWS SDK, boto3, or &lt;code&gt;aws&lt;/code&gt; CLI talk to it unchanged. The twist is that storage is scoped to a branch, so when you fork a database branch, its files fork with it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Neon AI Gateway&lt;/strong&gt; is a single credential that fronts models from Anthropic, OpenAI, Google, and a few open-source providers. The OpenAI and Anthropic SDKs work without code changes; you point them at a per-branch gateway endpoint. The published catalog lists around 25 models, priced per million tokens at what look like each provider's own list rates (Claude Haiku 4.5 at $1/$5 in/out, GPT-5 Nano at $0.05/$0.40, Gemini 2.5 Flash at $0.30/$2.50).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Neon Auth&lt;/strong&gt; rounds it out with authentication that does not require standing up a separate identity service, used in the realtime-chat template alongside Next.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  The through-line is branching
&lt;/h2&gt;

&lt;p&gt;Take those four features and the obvious read is "Neon is cloning Supabase," or "Neon is becoming Vercel with a database." Both are partly true and both miss the point. The organizing idea is that every one of these surfaces inherits database branching.&lt;/p&gt;

&lt;p&gt;A Neon branch already gave you an isolated copy of your data in milliseconds, with copy-on-write so it was cheap. Now that same branch gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an isolated &lt;strong&gt;function&lt;/strong&gt; at its own URL, running your latest code against that branch's data,&lt;/li&gt;
&lt;li&gt;an isolated &lt;strong&gt;storage&lt;/strong&gt; namespace, so files written in a preview branch never touch production objects,&lt;/li&gt;
&lt;li&gt;an isolated &lt;strong&gt;AI Gateway&lt;/strong&gt; endpoint, so model usage on a feature branch is its own thing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the part you cannot easily assemble from separate vendors. You can stitch Lambda, S3, an AI gateway, and an auth provider together yourself, plenty of teams have. What you cannot easily do is make all of them fork in lockstep when you open a pull request, and then throw the whole set away when the branch merges. The preview environment stops being "a copy of the database plus a pile of shared, mutable infrastructure" and becomes a genuinely isolated copy of the backend.&lt;/p&gt;

&lt;p&gt;If you have ever had a preview deployment write a test file into the production S3 bucket, or seen a staging job run up a bill against the same AI key as prod, you already understand why branch-scoped everything is the actual feature here.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it replaces, and the tax it removes
&lt;/h2&gt;

&lt;p&gt;The clearest way to see the value is to count the moving parts in a typical "branchable AI app" today versus on this platform. Standing up one environment the assemble-it-yourself way usually means a database, a compute host, an object store, a few model-provider keys, and an auth service, each with its own account, credential, and region to keep in sync.&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%2F3w93i5gb33fqgrnv86zl.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%2F3w93i5gb33fqgrnv86zl.png" alt="Illustrative count for a branchable AI app, not a benchmark." width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That count is illustrative, not measured: your stack may have more or fewer pieces. But the direction is the real claim. Every separate service is another credential to rotate, another thing to provision per preview environment, and another place for prod and staging to accidentally share state. Collapsing that to one account with auto-injected, per-branch credentials is less a feature than the removal of a tax you have been quietly paying.&lt;/p&gt;

&lt;p&gt;There is a second, quieter tax it removes: distance. Because functions run in the same region as the branch, the function-to-database round trip is local. A lot of "serverless Postgres is slow" folklore is really "my Lambda in one region is talking to my database in another, over a connection it has to re-establish on every cold start." Co-locating the compute with the branch sidesteps that specific problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the seams still show
&lt;/h2&gt;

&lt;p&gt;This is a private preview, and it reads like one. Worth being clear-eyed about the limits before you plan anything around it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One region, new projects only.&lt;/strong&gt; Everything is in AWS &lt;code&gt;us-east-2&lt;/code&gt; and only works on projects created after the preview opened. Your existing Neon databases will not grow these features in place, which matters if you were hoping to bolt functions onto a production project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Functions are not a job runner.&lt;/strong&gt; They are explicitly request/response and real-time, not background jobs. Queued, retryable, cancellable work still belongs to something like QStash or Inngest. That is an honest scoping decision, but it means "move my whole backend here" is not yet on the table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed function sizing.&lt;/strong&gt; Memory is fixed (2048 MiB at preview), so this is not a knob-for-everything compute platform yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Billing is half-documented.&lt;/strong&gt; The per-model token prices are public and look like pass-through, but Neon has not publicly spelled out whether there is a markup or preview credits on the AI Gateway. For a side project that is noise; for a budget forecast it is a question to ask before you commit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lock-in is the real trade.&lt;/strong&gt; The whole pitch is integration: one config file, one credential, everything branching together. That convenience is also coupling. An S3-compatible API and standard SDKs keep the exit ramps wider than a fully proprietary stack would, but a &lt;code&gt;neon.ts&lt;/code&gt; that declares your functions, buckets, and gateway is, by design, Neon-shaped.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who should actually care
&lt;/h2&gt;

&lt;p&gt;If you run a large, already-wired backend with mature infrastructure-as-code, none of this is urgent. You have solved preview environments, even if the solution is a pile of Terraform and a shared staging bucket.&lt;/p&gt;

&lt;p&gt;The teams this is aimed at are the ones for whom that pile is the problem. Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Anyone building agents.&lt;/strong&gt; An agent wants a database to remember things, compute that can stream tokens without a timeout, storage for what it generates, and model access. Getting all four from one CLI, branchable together, is a genuinely shorter path than assembling them. It is not a coincidence that the flagship templates are agents and MCP servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teams that live in preview environments.&lt;/strong&gt; If every pull request should get a real, isolated backend and yours currently get a database copy plus shared everything-else, branch-scoped functions and storage close that gap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small teams shipping AI features.&lt;/strong&gt; The combination of "Postgres you already use" and "model calls without managing three provider accounts" removes a couple of the most annoying setup steps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest framing is that Neon is making a bet: that the database, not the compute platform, is the right center of gravity for a backend, because the database is where your state and your branching already live. Vercel is making the opposite bet from the compute side, and Supabase has been making a similar bundled-backend bet for years. Whether "everything branches with your data" is a durable advantage or a feature others copy, the next year will tell.&lt;/p&gt;

&lt;p&gt;For now, the thing to internalize is that "Neon" no longer means "a Postgres host." It means a database with compute, storage, and model access growing out of it, all sharing the one trick Neon was already good at. If you have only ever evaluated it as a place to put a connection string, it is worth a second look on those terms.&lt;/p&gt;

&lt;p&gt;We benchmark Neon's database side in depth in our &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-free-tier-benchmarks" rel="noopener noreferrer"&gt;Neon vs Supabase series&lt;/a&gt;, and keep a running &lt;a href="https://devops-daily.com/comparisons/neon-vs-supabase" rel="noopener noreferrer"&gt;Neon vs Supabase comparison&lt;/a&gt; covering architecture and pricing side by side. As these platform features leave preview, we will put them through the same treatment: real projects, real numbers, and the harness published so you can argue with our data instead of someone's vibes.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>devops</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Stop Using Random UUIDs as Primary Keys: uuidv7() Lands in PostgreSQL 18</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Wed, 01 Jul 2026 15:26:27 +0000</pubDate>
      <link>https://dev.to/devopsdaily/stop-using-random-uuids-as-primary-keys-uuidv7-lands-in-postgresql-18-5fim</link>
      <guid>https://dev.to/devopsdaily/stop-using-random-uuids-as-primary-keys-uuidv7-lands-in-postgresql-18-5fim</guid>
      <description>&lt;p&gt;If you reach for &lt;code&gt;gen_random_uuid()&lt;/code&gt; every time you need a primary key, you have probably never measured what it costs. On a small table, nothing. On a table with tens of millions of rows, random UUIDs turn every insert into a random write into the middle of your primary-key index, and that quietly drags down insert throughput, inflates index size, and burns through cache and WAL.&lt;/p&gt;

&lt;p&gt;PostgreSQL 18 fixes the root cause with a native &lt;code&gt;uuidv7()&lt;/code&gt; function. UUIDv7 is time-ordered, so new keys land at the right-hand edge of the B-tree like a sequential &lt;code&gt;bigint&lt;/code&gt; would, while keeping the properties teams pick UUIDs for in the first place: generate them anywhere, no central sequence, no coordination. This post explains why the random version is slow, what changes with v7, the benchmark numbers on a 50-million-row table, the one real tradeoff, and how to adopt it without rewriting your schema.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;uuidv4()&lt;/code&gt; (random) primary keys scatter inserts across the whole index. On large tables that means constant page splits, low page density, fragmentation, and write amplification.&lt;/li&gt;
&lt;li&gt;PostgreSQL 18 adds &lt;code&gt;uuidv7()&lt;/code&gt;, a time-ordered UUID per &lt;a href="https://datatracker.ietf.org/doc/html/rfc9562" rel="noopener noreferrer"&gt;RFC 9562&lt;/a&gt;. New rows append at the index's right edge, like a sequential key.&lt;/li&gt;
&lt;li&gt;In one published 50M-row benchmark, the initial bulk insert finished in about 1.8 minutes with v7 versus about 20 minutes with v4, and the index was roughly 25 percent smaller. Range scans by id ran about 3x faster.&lt;/li&gt;
&lt;li&gt;The one real catch: a v7 value embeds its creation time, so do not hand it out as a public identifier if creation time is sensitive.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bigint&lt;/code&gt; is still smaller and faster than any UUID. Use &lt;code&gt;uuidv7()&lt;/code&gt; when you actually need UUID properties, not as a reflex.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL 18 (the &lt;code&gt;uuidv7()&lt;/code&gt; function is built in; no extension needed)&lt;/li&gt;
&lt;li&gt;Basic familiarity with B-tree indexes and primary keys&lt;/li&gt;
&lt;li&gt;A schema where you are choosing or reconsidering a primary-key type&lt;/li&gt;
&lt;li&gt;Optional: &lt;code&gt;pg_stat_statements&lt;/code&gt; and &lt;code&gt;\timing&lt;/code&gt; if you want to measure on your own data&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why random UUIDs are slow as primary keys
&lt;/h2&gt;

&lt;p&gt;A primary key in PostgreSQL is backed by a B-tree index, and a B-tree stays sorted by key. Where a new key lands in that sorted structure is the whole story.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;bigint&lt;/code&gt; from a sequence always sorts after the previous one, so every insert lands at the right-hand edge of the tree. That rightmost page stays hot in memory, fills up, and splits cleanly. A random UUIDv4 has no order at all, so each insert lands at a random leaf page somewhere in the index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UUIDv4 (random)                       UUIDv7 / bigint (ordered)
inserts scatter across the tree       inserts append at the right edge

      [ root ]                              [ root ]
     /   |   \                             /   |   \
  [p1] [p2] [p3] ...                    [p1] [p2] [p3] [hot]
   ^    ^      ^                                        ^
  write write write                              every write here
  (cold pages pulled in,                         (one hot page, stays
   split, half-empty)                             in cache, fills, splits clean)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That random-write pattern has three compounding costs on a large table:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Page splits and low density.&lt;/strong&gt; Inserting into the middle of a full page splits it, leaving both halves partly empty. Your index ends up larger than the data it indexes and full of slack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache misses.&lt;/strong&gt; The working set is the entire index, not a hot tail. Once the index no longer fits in &lt;code&gt;shared_buffers&lt;/code&gt;, every insert risks a random read from disk to fetch the target page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WAL and full-page-image amplification.&lt;/strong&gt; The first write to a page after a checkpoint logs the whole page. More distinct pages touched per second means more full-page images and more WAL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this shows up at 10,000 rows. It shows up exactly when the table gets big enough to matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What uuidv7() changes
&lt;/h2&gt;

&lt;p&gt;A UUIDv7 is laid out so the most significant bits are a timestamp. PostgreSQL 18 builds it from a 48-bit Unix millisecond timestamp, then a sub-millisecond fraction, then random bits, following RFC 9562. Because the timestamp is at the front and UUIDs sort lexically as 128-bit values, a v7 generated now always sorts after one generated a moment ago.&lt;/p&gt;

&lt;p&gt;The result is that v7 keys behave like a sequence for index-locality purposes. Inserts append at the right edge, the hot page stays in cache, and pages fill before they split. You get the write pattern of a &lt;code&gt;bigint&lt;/code&gt; with the generate-anywhere property of a UUID.&lt;/p&gt;

&lt;p&gt;PostgreSQL 18 exposes three functions. The names are now explicit about the version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Version 4, random. These two are equivalent.&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;gen_random_uuid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;-- 5b30857f-0bfa-48b5-ac0b-5c64e28078d1&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;uuidv4&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;               &lt;span class="c1"&gt;-- b42410ee-132f-42ee-9e4f-09a6485c95b8&lt;/span&gt;

&lt;span class="c1"&gt;-- Version 7, time-ordered. New in PostgreSQL 18.&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;uuidv7&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;               &lt;span class="c1"&gt;-- 019535d9-3df7-79fb-b466-fa907fa17f9e&lt;/span&gt;

&lt;span class="c1"&gt;-- Optional interval shift, handy for backfilling historical rows&lt;/span&gt;
&lt;span class="c1"&gt;-- with timestamps in the past.&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;uuidv7&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'-7 days'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One useful detail: within a single backend session, PostgreSQL guarantees each &lt;code&gt;uuidv7()&lt;/code&gt; it generates is strictly greater than the last, by spending some of the random bits on extra clock precision. So even a tight insert loop produces monotonic keys rather than occasionally colliding on the same millisecond.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;The performance argument is not subtle. Credativ published a &lt;a href="https://www.credativ.de/en/blog/postgresql-en/a-deeper-look-at-old-uuidv4-vs-new-uuidv7-in-postgresql-18/" rel="noopener noreferrer"&gt;detailed comparison on PostgreSQL 18&lt;/a&gt; using a single-column UUID primary key and 50 million rows. The initial bulk load is the headline:&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%2Ffs8y7swfd5tbcrzyyqxd.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%2Ffs8y7swfd5tbcrzyyqxd.png" alt="Time to insert 50M rows into an empty table" width="799" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The index size gap is just as real, and it widens when you insert into a table that already holds data, which is the normal case in production:&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%2F0j41ec6rsknmg9v9l7ya.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%2F0j41ec6rsknmg9v9l7ya.png" alt="Primary-key index size after inserting 50M rows" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reads benefit too. In the same benchmark, a range scan ordered by the id column ran roughly three times faster on v7 (about 113 ms versus 318 ms for a million-row &lt;code&gt;ORDER BY id&lt;/code&gt;) and needed on the order of 100 times fewer buffer hits, because rows created near each other in time also sit near each other on disk. That locality is something a random UUID can never give you.&lt;/p&gt;

&lt;p&gt;Two caveats on the numbers. They come from one benchmark on a synthetic single-column table, so treat the exact figures as directional rather than a promise for your workload. And the gap is smallest on tiny tables and largest on big ones, which is the whole point: this is a problem that scales with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  uuidv7 vs uuidv4 vs bigint
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;uuidv7()&lt;/code&gt; is not automatically the right choice. It sits between the other two options.&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;bigint sequence&lt;/th&gt;
&lt;th&gt;uuidv4 (random)&lt;/th&gt;
&lt;th&gt;uuidv7 (time-ordered)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td&gt;8 bytes&lt;/td&gt;
&lt;td&gt;16 bytes&lt;/td&gt;
&lt;td&gt;16 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insert locality&lt;/td&gt;
&lt;td&gt;Sequential (best)&lt;/td&gt;
&lt;td&gt;Random (worst)&lt;/td&gt;
&lt;td&gt;Sequential&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generate without the DB&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reveals row count or order&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Partially (creation time)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Leaks creation time&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The short version:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reach for &lt;code&gt;bigint&lt;/code&gt;&lt;/strong&gt; when a single database owns the sequence and you do not need to generate ids elsewhere. It is half the size of any UUID and the fastest option. The downside is that sequential integers leak how many rows you have and are trivially enumerable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reach for &lt;code&gt;uuidv7()&lt;/code&gt;&lt;/strong&gt; when you want UUIDs: ids generated by clients or multiple services, merged across shards, or created before a row reaches the database. It gives you that with almost none of the write penalty of v4.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reach for &lt;code&gt;uuidv4()&lt;/code&gt;&lt;/strong&gt; only when you specifically need an identifier that reveals nothing, including when the row was created.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The one real catch: v7 leaks creation time
&lt;/h2&gt;

&lt;p&gt;Because the timestamp sits in the high bits, anyone holding a v7 value can read roughly when it was generated. That is fine for an internal primary key. It is not fine if you expose the same value as a public identifier and the creation time is sensitive, for example a user id where signup time is private, or an order id where a competitor could infer your daily volume by diffing two ids.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not assume a UUID is opaque just because it looks random. A &lt;code&gt;uuidv7()&lt;/code&gt; embeds a millisecond timestamp you can decode in seconds. If an identifier is shown to users or third parties and its creation time is sensitive, keep &lt;code&gt;uuidv7()&lt;/code&gt; as the internal primary key and expose a separate &lt;code&gt;uuidv4()&lt;/code&gt; (or another opaque token) externally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a design decision, not a reason to avoid v7. Most primary keys never leave the backend, and for those the timestamp is a feature, not a leak.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to adopt it
&lt;/h2&gt;

&lt;p&gt;For new tables, set the column default and move on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;          &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;uuidv7&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;total_cents&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt;  &lt;span class="n"&gt;timestamptz&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_cents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuidv7&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;4999&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;RETURNING&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an existing table that already uses random UUIDs, you do not need a risky rewrite. The existing rows keep their v4 values and stay scattered, but every new row inserted with a v7 default lands in order, so the index stops degrading from that point forward. Switch the default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- New rows get time-ordered ids; old rows are untouched.&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;uuidv7&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want the full benefit on historical data, you can rebuild the table or index during a maintenance window so the existing rows are stored in key order, but for many teams simply changing the default and letting the table grow in order is enough.&lt;/p&gt;

&lt;p&gt;A few adoption notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application-side generation still works.&lt;/strong&gt; If your services generate ids before inserting, switch the client library to a UUIDv7 generator. Most language ecosystems now have one, and the database does not care who produced the value as long as it is a valid v7.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORMs are catching up.&lt;/strong&gt; Check whether your ORM lets you set a database default expression for the id column; if so, &lt;code&gt;DEFAULT uuidv7()&lt;/code&gt; is the cleanest path. If it generates ids in application code, point it at a v7 library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You do not need PostgreSQL 18 to start.&lt;/strong&gt; If you are on 14 to 17, you can adopt UUIDv7 today by generating it in the application or with a small SQL function, then the upgrade to 18 just lets you drop that shim for the native function. Plenty of managed Postgres is already on 18 as well (Neon, for example, defaults new projects to Postgres 18), so you can try &lt;code&gt;uuidv7()&lt;/code&gt; on a fresh database without upgrading anything yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Random UUIDv4 primary keys are a silent scaling tax: random index writes mean page splits, bloated indexes, cache misses, and extra WAL once a table gets large.&lt;/li&gt;
&lt;li&gt;PostgreSQL 18's &lt;code&gt;uuidv7()&lt;/code&gt; is time-ordered, so inserts append at the index edge like a sequence while keeping the generate-anywhere property of a UUID. Published benchmarks show large insert-time and index-size wins on 50M rows.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bigint&lt;/code&gt; is still the smallest and fastest key when one database owns the sequence; use &lt;code&gt;uuidv7()&lt;/code&gt; when you genuinely need UUIDs, and &lt;code&gt;uuidv4()&lt;/code&gt; only when you must hide creation time.&lt;/li&gt;
&lt;li&gt;Adopting it is a one-line default change for new rows, with no rewrite required for existing tables. The main thing to design around is that v7 embeds a decodable timestamp, so keep it off public-facing identifiers when that matters.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>developer</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Neon vs Supabase Pricing: What the Same App Costs From Launch to Scale</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Fri, 26 Jun 2026 13:54:18 +0000</pubDate>
      <link>https://dev.to/devopsdaily/neon-vs-supabase-pricing-what-the-same-app-costs-from-launch-to-scale-255g</link>
      <guid>https://dev.to/devopsdaily/neon-vs-supabase-pricing-what-the-same-app-costs-from-launch-to-scale-255g</guid>
      <description>&lt;p&gt;Pricing pages answer the question "what does a unit cost". They are conspicuously silent on the question you actually have: "what will my application cost in a year, when it has real users?" The honest answer depends on workload shape, and workload shape changes as you grow, which is why the same two platforms can each be the cheap option at different points in the same product's life.&lt;/p&gt;

&lt;p&gt;This is part three of our Neon vs Supabase series (&lt;a href="https://devops-daily.com/posts/neon-vs-supabase-free-tier-benchmarks" rel="noopener noreferrer"&gt;free tiers&lt;/a&gt;, &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-operational-benchmarks" rel="noopener noreferrer"&gt;operational benchmarks&lt;/a&gt;). Instead of benchmarking operations, we built a cost model: one application, five growth stages, priced on Neon Launch and Supabase Pro using list prices we verified against both pricing pages this week. The model is &lt;a href="https://github.com/The-DevOps-Daily/serverless-postgres-benchmarks" rel="noopener noreferrer"&gt;open source in the same repo&lt;/a&gt; as the benchmarks (&lt;code&gt;npm run costs&lt;/code&gt;), every price carries its source, and you can change the workload assumptions and rerun it for your own product.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;There are &lt;strong&gt;three cost regimes, not one winner&lt;/strong&gt;: Neon wins early (scale-to-zero means a quiet app costs almost nothing), Supabase wins the middle (a flat fee beats usage billing once the database runs hot but small), and Neon wins at scale by a wide margin.&lt;/li&gt;
&lt;li&gt;The two &lt;strong&gt;crossover points&lt;/strong&gt; sit roughly where your app stops sleeping (Supabase becomes competitive) and where your user count passes Supabase's included 100k monthly active users (Supabase stops being competitive, fast).&lt;/li&gt;
&lt;li&gt;The scale-stage surprise: on Supabase, &lt;strong&gt;the database is not the bill&lt;/strong&gt;. Metered auth MAU is. Our scale stage prices at $1,213/month on Supabase Pro, of which $975 is MAU overage; the same stage on Neon Launch is $278, because Neon Auth carries no per-MAU meter up to 1M users.&lt;/li&gt;
&lt;li&gt;This comparison assumes you use each platform's bundled auth. If you bring your own auth provider, the picture changes substantially in Supabase's favor, and we show you where.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The application and its growth
&lt;/h2&gt;

&lt;p&gt;The model prices one hypothetical B2B SaaS through five stages, with the workload dimensions both platforms bill on: average compute demand, how much of the month the database is actually active, database size, monthly active users on auth, preview branches created by CI, and egress.&lt;/p&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;Compute (avg)&lt;/th&gt;
&lt;th&gt;Active time&lt;/th&gt;
&lt;th&gt;DB size&lt;/th&gt;
&lt;th&gt;MAU&lt;/th&gt;
&lt;th&gt;Branches/mo&lt;/th&gt;
&lt;th&gt;Egress&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Launch month&lt;/td&gt;
&lt;td&gt;0.25 CU&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;5 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First customers&lt;/td&gt;
&lt;td&gt;0.25 CU&lt;/td&gt;
&lt;td&gt;45%&lt;/td&gt;
&lt;td&gt;5 GB&lt;/td&gt;
&lt;td&gt;5k&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;25 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product-market fit&lt;/td&gt;
&lt;td&gt;0.5 CU&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;20 GB&lt;/td&gt;
&lt;td&gt;30k&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;100 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Growth&lt;/td&gt;
&lt;td&gt;1 CU&lt;/td&gt;
&lt;td&gt;95%&lt;/td&gt;
&lt;td&gt;60 GB&lt;/td&gt;
&lt;td&gt;120k&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;400 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale&lt;/td&gt;
&lt;td&gt;2 CU&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;200 GB&lt;/td&gt;
&lt;td&gt;400k&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;1.5 TB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Disagree with the assumptions? Good: they are parameters, not conclusions. Clone the repo, edit the scenario, rerun. The shape of the findings survives reasonable changes to the numbers; your exact crossover points will differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  The curves
&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%2F4534sihbrrks2nclaahi.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%2F4534sihbrrks2nclaahi.png" alt="Monthly cost of the same application as it grows" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Monthly cost of the same application as it grows — &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-scaling-costs" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regime one, the quiet months.&lt;/strong&gt; At launch, Neon costs $5 to Supabase's $26. Nothing clever: Supabase Pro is a $25 flat fee plus always-on compute, while Neon bills compute only when the database is awake, and an early-stage app sleeps most of the month. If you are pre-revenue, this gap is your hosting budget.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regime two, the flat-fee window.&lt;/strong&gt; By product-market fit the picture inverts: Supabase $33, Neon $49. The database now runs three-quarters of the month, so scale-to-zero stops paying, while Supabase's fixed fee covers a Small instance running around the clock with most usage inside included quotas. This is the regime Supabase's pricing is designed for, and in it, the design works. The growth stage is nearly a tie ($128 vs $120), which is itself useful information: between roughly 30k and 120k users, price should not be the deciding factor at all; pick on the &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-operational-benchmarks" rel="noopener noreferrer"&gt;operational differences&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regime three, the meters.&lt;/strong&gt; At scale the curves split violently: $278 on Neon, $1,213 on Supabase. To see why, look at where the Supabase dollars go:&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%2Fg8d1tlk65bz4yijerl05.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%2Fg8d1tlk65bz4yijerl05.png" alt="Where the money goes at the scale stage (Supabase Pro, $1213.39/mo total)" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Where the money goes at the scale stage (Supabase Pro, $1213.39/mo total) — &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-scaling-costs" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The MAU surprise
&lt;/h2&gt;

&lt;p&gt;That chart is the article. At 400k monthly active users, the compute (a Medium instance, $50 after credits) and even 200 GB of storage ($24) are rounding errors next to &lt;strong&gt;$975 of MAU overage&lt;/strong&gt;: Supabase Auth includes 100k monthly active users on Pro and bills $0.00325 for each one beyond. Auth, the feature that felt free when you started, becomes 80% of the bill precisely when your product succeeds.&lt;/p&gt;

&lt;p&gt;Neon's side has no equivalent meter: Neon Auth (in beta) carries no per-MAU billing up to one million users on the paid plans, so the scale stage is honest compute and storage: $155 + $70 + $53 of always-active database, branches included.&lt;/p&gt;

&lt;p&gt;Now the fairness flip, because this cuts both ways: &lt;strong&gt;the comparison above assumes you use the bundled auth.&lt;/strong&gt; Plenty of teams run Clerk, Auth0, WorkOS, or their own auth regardless of database, and at 400k MAU those run hundreds to thousands of dollars a month on their own. If you bring your own auth, delete the MAU line from the Supabase column, and the scale stage becomes roughly $238 vs $278: a near-tie that Supabase arguably wins. The platform decision and the auth decision are one decision wearing two coats; make them together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the model deliberately leaves out
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The PITR add-on&lt;/strong&gt; ($100/month on Supabase per 7-day window): add it if sub-minute recovery is a requirement; part two explains what you get on each platform without it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replacement costs for the rest of the bundle&lt;/strong&gt;: if you would otherwise pay for storage, realtime, or edge functions separately, Supabase's flat fee is buying more than a database. Neon announced its own storage and functions in June 2026, but they have not shipped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Committed-use and enterprise discounts&lt;/strong&gt;, support tiers, and the Team/Scale tiers above these plans: that comparison is coming later in this series.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Egress shape&lt;/strong&gt;: we model it linearly; a media-heavy product will not be linear, and Supabase's $0.09/GB beyond 250 GB deserves your own modeling if that is you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to actually use this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Find your regime. Mostly-idle side project or pre-launch: Neon by default. Steady small production app, happy inside included quotas: Supabase's flat fee is genuinely good value. Past 100k MAU on bundled auth: do the math before the bill does it for you.&lt;/li&gt;
&lt;li&gt;Watch the crossovers, not the platforms. The first crossover arrives when your database stops sleeping; the second when your user count crosses the included-MAU line. Both are visible in your own metrics months before they hit the invoice.&lt;/li&gt;
&lt;li&gt;Decide auth and database together. The single biggest line in this entire analysis is an auth meter on a database platform.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every price in the model links to its source and was verified against both pricing pages in June 2026 (prices change; the &lt;a href="https://github.com/The-DevOps-Daily/serverless-postgres-benchmarks" rel="noopener noreferrer"&gt;repo&lt;/a&gt; holds the dated record). Like the benchmarks, the model is open source and contributions are welcome: if a price moved or an assumption looks wrong, open an issue or PR and we will rerun the curves. The &lt;a href="https://postgres-benchmarks.devops-daily.com/" rel="noopener noreferrer"&gt;live dashboard&lt;/a&gt; carries the measured performance data this series is built on, our &lt;a href="https://devops-daily.com/comparisons/neon-vs-supabase" rel="noopener noreferrer"&gt;full Neon vs Supabase comparison&lt;/a&gt; lays out the architecture and feature differences side by side, and part four will close the series with something nobody has benchmarked properly yet: what it costs in AI agent tokens to build the same application on each platform.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>neon</category>
      <category>supabase</category>
      <category>database</category>
    </item>
    <item>
      <title>Neon vs Supabase in Production: We Benchmarked the Operations That Page You at 3am</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Thu, 25 Jun 2026 15:57:46 +0000</pubDate>
      <link>https://dev.to/devopsdaily/neon-vs-supabase-in-production-we-benchmarked-the-operations-that-page-you-at-3am-4ei8</link>
      <guid>https://dev.to/devopsdaily/neon-vs-supabase-in-production-we-benchmarked-the-operations-that-page-you-at-3am-4ei8</guid>
      <description>&lt;p&gt;Free tiers are where you evaluate a database. Paid tiers are where you operate one, and operating means the unglamorous verbs: resize the compute because traffic doubled, add a read replica because the dashboard queries are hurting, branch the database for a preview environment, restore because someone ran the wrong migration. Vendor documentation describes these operations. It rarely tells you how long they take, and it almost never tells you what they cost in downtime.&lt;/p&gt;

&lt;p&gt;So we measured them. This is part two of our Neon vs Supabase series (&lt;a href="https://devops-daily.com/posts/neon-vs-supabase-free-tier-benchmarks" rel="noopener noreferrer"&gt;part one covered the free tiers&lt;/a&gt;), now on the plans you would actually run production on: Supabase Pro against the equivalent Neon tier. Same methodology as before: both platforms in AWS eu-central-1, timed from a client VM in the same metro, every operation run repeatedly across two separate benchmark sessions on different days, raw samples committed, and everything reproducible from &lt;a href="https://github.com/The-DevOps-Daily/serverless-postgres-benchmarks" rel="noopener noreferrer"&gt;the open source harness&lt;/a&gt; with a &lt;a href="https://postgres-benchmarks.devops-daily.com/" rel="noopener noreferrer"&gt;live dashboard&lt;/a&gt; tracking every session since.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compute resize is the starkest difference we have ever measured between two managed databases.&lt;/strong&gt; Changing compute size on Supabase took 39 seconds of API time and caused 39 seconds of real SQL downtime per change, measured by probing the database every 250ms. The same operation on Neon: 2.4 seconds to apply, zero failed probes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You also cannot resize Supabase twice in a row&lt;/strong&gt;: the platform throttles consecutive compute changes for minutes ("We are still processing addon changes, please try again in 3 minutes").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read replicas are an architecture lesson in two numbers&lt;/strong&gt;: 8 seconds on Neon (a new compute attaches to existing shared storage) vs 181 seconds on Supabase (a full database clone), with Supabase also requiring Small compute or larger on the primary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branching held its free-tier shape&lt;/strong&gt;: a Neon branch arrives carrying the parent's 100k rows in 1.7s; a Supabase branch arrives schema-only in 6.2-6.7s. Supabase's API now has a with_data flag, but every attempt returned 406 "Failed to fetch latest physical backup" on a fresh project: data branches have infrastructure prerequisites.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Under connection stampedes the platforms are twins&lt;/strong&gt;: 50, 100, and 200 simultaneous cold connections produced near-identical wave times and zero refusals on both.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How we measured
&lt;/h2&gt;

&lt;p&gt;Every number below is the median of repeated runs (10 per operation per session for management operations, 5 waves per concurrency level), collected in two independent sessions on consecutive days. The two sessions agreed within single-digit percentages on every operation, which is the property that makes medians worth publishing. The client sat 1-2ms from both platforms. Resources were created fresh and torn down after every run.&lt;/p&gt;

&lt;p&gt;One honest note on plans: the Supabase side ran on Pro ($25/month). The Neon side ran on a Scale-plan account, but every operation measured here (branching, resize, replicas, restore) behaves identically on Launch; plan tier changes quotas and retention windows, not the mechanics we timed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compute resize: the 3am operation
&lt;/h2&gt;

&lt;p&gt;You sized the database for launch traffic. Launch went well. Now you need the next compute size, and the question that matters is not "can the platform do it" but "what happens to my users while it does".&lt;/p&gt;

&lt;p&gt;We resized each platform's compute up and back down, ten cycles per session, while a probe ran &lt;code&gt;select 1&lt;/code&gt; against the database every 250 milliseconds. Two numbers per resize: how long until the management API reported the change applied, and how long SQL actually failed.&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%2Fkg1cw0nn9n3jjf4vba72.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%2Fkg1cw0nn9n3jjf4vba72.png" alt="Compute resize: API apply time vs actual SQL outage (median)" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Compute resize: API apply time vs actual SQL outage (median) — &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-operational-benchmarks" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Neon applies an autoscaling-limit change in 2.4 seconds, and across forty resize cycles in two sessions, &lt;strong&gt;the probe never failed once&lt;/strong&gt;. The compute reconfigures behind the same endpoint without dropping the connection path. Supabase restarts the database to change compute: 39 seconds of apply time, and effectively all of it is real downtime; their docs say resizes are "usually applied with less than 2 minutes of downtime", and our measurements land comfortably inside that promise while still being 39 seconds of failed queries per change.&lt;/p&gt;

&lt;p&gt;The second finding is subtler and bit us during the benchmark itself: &lt;strong&gt;Supabase refuses back-to-back compute changes&lt;/strong&gt;. Issue two resizes in quick succession and the API returns "We are still processing addon changes, please try again in 3 minutes", and the project reports an unhealthy state between changes. For a production runbook this means a Supabase resize is a planned, serialized event with a maintenance-window mindset. On Neon it is closer to a config tweak.&lt;/p&gt;

&lt;p&gt;If your workload's compute needs change often (and on serverless-adjacent platforms, that is the promise), this section is the comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  Branching: same story, sharper edges
&lt;/h2&gt;

&lt;p&gt;Part one covered free-tier branching; the paid tiers sharpen it. A Neon branch is a copy-on-write reference to the parent's storage: it arrives carrying all data. A Supabase branch is a freshly provisioned project that replays schema and config: it arrives empty of data, on Pro as on free.&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%2F2gecs6wv5jp00c5tdj7z.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%2F2gecs6wv5jp00c5tdj7z.png" alt="Branch to queryable: Neon copies 100k rows, Supabase copies schema only" width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Branch to queryable: Neon copies 100k rows, Supabase copies schema only: &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-operational-benchmarks" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Medians: 1.7 seconds for a Neon branch with 100,000 rows of parent data, 6.2-6.7 seconds for a Supabase schema-only branch. Both respectable. Two asterisks worth your attention though:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tail.&lt;/strong&gt; In session one, nine Supabase branches took 6-8 seconds and one took &lt;strong&gt;146 seconds&lt;/strong&gt;, with nothing different about the request. Session two had no such outlier, which is exactly why we run multiple sessions. If your CI creates a branch per pull request, a 2.5-minute outlier is the kind of thing that makes a developer rerun the pipeline and file a flaky-infra ticket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The with_data flag.&lt;/strong&gt; Supabase's branch API accepts &lt;code&gt;with_data: true&lt;/code&gt;, which on paper would close the data gap. In practice, every attempt on our freshly created projects failed with 406 "Failed to fetch latest physical backup": data branches require the project to already have physical backups, which fresh projects do not have and which normally arrives with the PITR add-on. For the create-test-destroy loop that makes branching valuable, data-included branches on Supabase have prerequisites that defeat the purpose today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read replicas: attach vs clone
&lt;/h2&gt;

&lt;p&gt;Adding a read replica is where the two architectures stop being abstract diagrams and start being your wait time.&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%2Fr93kkq4kv32of94ka661.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%2Fr93kkq4kv32of94ka661.png" alt="Read replica to first query" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read replica to first query: &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-operational-benchmarks" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Neon: 8 seconds median to a replica answering queries. There is nothing to copy; a read-only compute attaches to the same shared storage as the primary, so replica creation is compute provisioning, full stop. It also means no replication lag in the classic sense and no extra storage bill.&lt;/p&gt;

&lt;p&gt;Supabase: 181 seconds median, remarkably consistent (our session-one runs landed within a 2-second band of each other), because each replica is a physical clone of the database with WAL streaming, the way RDS would do it. Two operational prerequisites we hit: the primary must run Small compute or larger (the API rejects replicas on Micro with "Read replicas require a minimum size of small"), and replica disk bills at 1.25x the primary's size.&lt;/p&gt;

&lt;p&gt;Neither approach is wrong. Clones isolate replicas from primary storage performance; shared storage makes replicas instant and cheap. But if your scaling playbook says "add a replica when read latency climbs", one platform executes that play in seconds and the other in minutes, and the minutes version also costs a compute-size bump if you started small.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does any of this scale with database size?
&lt;/h3&gt;

&lt;p&gt;The attach-vs-clone story makes a testable prediction: copy-on-write operations should stay flat as the database grows, physical clones should not. So we reran branches and replicas at 100k, 1M, and 5M seeded rows, a 50x span.&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%2F4kt91prk153mfxf33x8e.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%2F4kt91prk153mfxf33x8e.png" alt="Read replica creation as the database grows" width="799" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read replica creation as the database grows — &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-operational-benchmarks" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The prediction holds, with one nuance. Neon branches are flat to the decimal (1.73s, 1.67s, 1.67s) and so are its replicas (7.9s, 8.0s, 8.2s): there is nothing that copies data, so data size cannot matter. Supabase branches are also flat at 6.4s, but for the less flattering reason that they only copy schema. Supabase replicas are the one operation where size shows: the median grew 12% by 5M rows and p95 stretched from 182s to 234s. At a few hundred megabytes, provisioning still dominates the clone; at real production sizes, the copy takes over and that line keeps climbing. Our benchmark budget stops at 5M rows, but the direction is unambiguous, and it compounds the playbook problem above: the moment you most need a replica is the moment your database is biggest.&lt;/p&gt;

&lt;h2&gt;
  
  
  The connection stampede: a tie worth publishing
&lt;/h2&gt;

&lt;p&gt;Serverless platforms fail in bursts: two hundred function invocations wake at once and all of them want a connection. We simulated exactly that through each platform's transaction pooler: N simultaneous cold connections, each performing connect, TLS, auth, one query, disconnect.&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%2Fhcn2khsmmlookdgnrurq.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%2Fhcn2khsmmlookdgnrurq.png" alt="Connection stampede: N simultaneous cold connections through the pooler (median wave)" width="799" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Connection stampede: N simultaneous cold connections through the pooler (median wave) — &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-operational-benchmarks" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Both platforms absorb a 200-connection stampede in about a second, scaling near-linearly from 50 to 200 clients, with &lt;strong&gt;zero refused connections at any level on either platform&lt;/strong&gt;. Supabase's Supavisor was a hair faster at every level; the margin is noise. After the resize and replica sections, it would be easy to expect Neon to win everything; this is the result that says the comparison is about architecture, not quality. Both teams have built excellent poolers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Restore: the operation you hope never to time
&lt;/h2&gt;

&lt;p&gt;We restored Neon branches to a point 60 seconds in the past, with 100k rows of data, eight runs per session: &lt;strong&gt;5.6 to 6.9 seconds median&lt;/strong&gt; until the management API confirmed completion and SQL answered on the restored state. That is point-in-time recovery at interactive speed, and it comes included.&lt;/p&gt;

&lt;p&gt;On Supabase, point-in-time recovery is a $100/month add-on (per 7-day retention window, Small compute minimum), so we documented it rather than benchmarked it; daily backups are included on Pro but a daily backup is a very different promise from PITR when the bad migration ran at 14:47. If sub-minute-granularity recovery matters to your operation, price the add-on into the comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  The finding we didn't go looking for
&lt;/h2&gt;

&lt;p&gt;While rechecking our own dashboard we noticed something odd: project creation on the Supabase Pro org was wildly slower than the free-org numbers from part one. So we measured it properly, twice, a day apart.&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%2Fn5tq2e9q2jmhu4nzut6b.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%2Fn5tq2e9q2jmhu4nzut6b.png" alt="Supabase project creation to first query, free org vs Pro org" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Supabase project creation to first query, free org vs Pro org — &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-operational-benchmarks" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Free org: &lt;strong&gt;7.4 seconds median&lt;/strong&gt; to a queryable project. Pro org: &lt;strong&gt;125.2 seconds&lt;/strong&gt; on day one (20 runs) and &lt;strong&gt;111.9 seconds&lt;/strong&gt; on day two (10 runs), so this is not a one-day capacity blip. Day two also produced two provisioning failures we did not cause: one project came up with no pooler configuration, and another returned 404 on its own ref immediately after creation. Neon, measured the same morning as a control, created projects in 5.5 seconds with no failures.&lt;/p&gt;

&lt;p&gt;We do not know why paid-org provisioning is 15x slower than free; nothing in the documentation suggests it should be. If your platform automation creates Supabase projects programmatically (per-tenant databases, ephemeral environments), budget two minutes and a retry loop, not eight seconds. We have raw samples committed for all three sessions and would genuinely welcome an explanation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What failed, and what it taught us
&lt;/h2&gt;

&lt;p&gt;A benchmark that reports only clean numbers is hiding something. Ours hit three walls worth knowing about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supabase's addon pipeline throttling (above) means resize benchmarks, and resize automation, must wait minutes between changes.&lt;/li&gt;
&lt;li&gt;Supabase Management API mutations sometimes return empty response bodies, and replica setup reports no status; readiness means polling the pooler config until a READ_REPLICA entry appears. Automation against these APIs needs more defensive plumbing than Neon's operations API, which returns explicit operation objects with terminal states.&lt;/li&gt;
&lt;li&gt;A long-running idle Postgres connection on either platform will emit asynchronous errors when the server restarts under it (compute resize, for instance). If your Node service holds connections through a Supabase resize, handle the &lt;code&gt;error&lt;/code&gt; event on your clients or the restart will take your process down with it. Ask us how we know.&lt;/li&gt;
&lt;li&gt;One more finding was waiting after the benchmarks ended. With every benchmark project torn down and the organization verifiably empty (&lt;code&gt;GET /v1/projects&lt;/code&gt; and the org-scoped listing both return zero projects), downgrading the org from Pro was refused with "You still have active preview branches. Please delete all your preview branches and disable branching feature before downgrading to Free Plan." No projects exist, so no branches can: the downgrade validator appears to count orphaned branch records left behind when branches' parent projects are deleted. If you run branch-heavy ephemeral workloads on a paid org and ever plan to downgrade it, know that the exit door can be blocked by data you can no longer see or delete.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;The free-tier conclusion was "pick on shape, not speed". The production-tier conclusion is sharper: &lt;strong&gt;the operational gap is real, and it favors Neon almost everywhere it exists&lt;/strong&gt;. Resize without downtime vs a 39-second outage with a minutes-long cooldown; replicas in 8 seconds vs 3 minutes with compute prerequisites; branches with data vs without; included interactive PITR vs a $100/month add-on. The one place the platforms tie (connection stampedes) is the one place most teams assumed serverless Postgres would struggle, and neither does.&lt;/p&gt;

&lt;p&gt;What this verdict does not say: Supabase Pro still bundles auth, storage, realtime, and edge functions that Neon does not have today (announced, not shipped), and part one's conclusion stands: teams shipping a v1 product buy real velocity with that bundle. But if the database is the load-bearing component of your operation and you expect to resize, replicate, branch, and occasionally restore it, the operational benchmarks have a clear winner.&lt;/p&gt;

&lt;p&gt;Every number above links to raw committed samples, the &lt;a href="https://postgres-benchmarks.devops-daily.com/" rel="noopener noreferrer"&gt;live dashboard&lt;/a&gt; updates with every benchmark session, and the &lt;a href="https://github.com/The-DevOps-Daily/serverless-postgres-benchmarks" rel="noopener noreferrer"&gt;harness is open source&lt;/a&gt;: if you see something off in the methodology or get different numbers, open an issue or a pull request, corrections are welcome and credited. For the architectural side by side rather than the timings, our &lt;a href="https://devops-daily.com/comparisons/neon-vs-supabase" rel="noopener noreferrer"&gt;full Neon vs Supabase comparison&lt;/a&gt; covers pricing models, PITR, and the bundled features in one place. Part three prices all of this against a growing application, including the cost crossover points nobody talks about.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>neon</category>
      <category>supabase</category>
      <category>database</category>
    </item>
    <item>
      <title>Hetzner Doubled Its Prices Again. The AI Memory Crunch Is Why</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Tue, 23 Jun 2026 12:25:30 +0000</pubDate>
      <link>https://dev.to/devopsdaily/hetzner-doubled-its-prices-again-the-ai-memory-crunch-is-why-64b</link>
      <guid>https://dev.to/devopsdaily/hetzner-doubled-its-prices-again-the-ai-memory-crunch-is-why-64b</guid>
      <description>&lt;p&gt;If you run anything on Hetzner, you have probably already seen the notice. As of 08:00 CEST on June 15, 2026, &lt;a href="https://docs.hetzner.com/general/infrastructure-and-availability/price-adjustment/" rel="noopener noreferrer"&gt;Hetzner adjusted its prices&lt;/a&gt; again, and this round is the steepest yet: new cloud and dedicated server orders are up by an average of about 99% in Germany, 158% in its US locations, and 78% in Singapore, &lt;a href="https://www.heise.de/en/news/Up-to-200-percent-Cloud-hoster-Hetzner-adjusts-prices-again-11333037.html" rel="noopener noreferrer"&gt;according to heise&lt;/a&gt;. Some line items more than tripled.&lt;/p&gt;

&lt;p&gt;For a host whose entire brand is "absurdly cheap European iron," a near-doubling is a shock. But the interesting part for anyone who runs infrastructure is not the number. It is the reason behind it, because that reason is going to show up in your bills too, whether or not you host on Hetzner and whether or not you do anything with AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually changed
&lt;/h2&gt;

&lt;p&gt;The adjustment applies to &lt;strong&gt;new orders and cloud rescales&lt;/strong&gt; from June 15 onward. If you have an existing machine, you keep your current price until you reorder or resize it. Orders placed before the cutoff but delivered after still get the old price. Web hosting, managed and Exchange servers, IP addresses, storage boxes, and load balancers were left out of this round.&lt;/p&gt;

&lt;p&gt;A few representative changes, taken from Hetzner's own price tables and heise's reporting:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CAX11 (ARM, DE/FI)&lt;/td&gt;
&lt;td&gt;€4.49/mo&lt;/td&gt;
&lt;td&gt;€5.99/mo&lt;/td&gt;
&lt;td&gt;+33%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CCX13 (dedicated vCPU, DE/FI)&lt;/td&gt;
&lt;td&gt;€15.99/mo&lt;/td&gt;
&lt;td&gt;€42.99/mo&lt;/td&gt;
&lt;td&gt;+169%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPX41 (US region)&lt;/td&gt;
&lt;td&gt;€38.99/mo&lt;/td&gt;
&lt;td&gt;€120.49/mo&lt;/td&gt;
&lt;td&gt;+209%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two patterns are worth pulling out of that table. The ARM line (CAX) took by far the smallest hit. The x86 dedicated-vCPU lines, the ones that come with more memory attached, took the largest. And US capacity rose far more than European, which tracks with where new hardware is hardest to get right now.&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%2Fmokifwr9qoaetasu78ta.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%2Fmokifwr9qoaetasu78ta.png" alt=" " width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is also not a one-off. By several outlets' count it is the third price adjustment Hetzner has made in 2026, after a round on April 1 that raised cloud servers 30 to 43%, object storage 30 to 53%, and, most tellingly, memory add-ons by around 575%. The "again" in everyone's reaction is earned.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real story is in the memory market
&lt;/h2&gt;

&lt;p&gt;Hetzner's stated reason is "extremely high procurement costs for new hardware." That is true, and it undersells how unusual the moment is. The component market is in the middle of what the industry is openly calling an AI supercycle, and the prices are genuinely historic.&lt;/p&gt;

&lt;p&gt;The numbers behind the headlines, from &lt;a href="https://www.tomshardware.com/pc-components/storage/perfect-storm-of-demand-and-supply-driving-up-storage-costs" rel="noopener noreferrer"&gt;Tom's Hardware&lt;/a&gt;, &lt;a href="https://spectrum.ieee.org/dram-shortage" rel="noopener noreferrer"&gt;IEEE Spectrum&lt;/a&gt;, and TrendForce data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DRAM and NAND prices rose between 50% and 200% in the first half of 2026, with DRAM up roughly 171% year over year.&lt;/li&gt;
&lt;li&gt;AI data centers are projected to consume around 70% of high-end DRAM output in 2026, an inversion of who the memory makers used to build for.&lt;/li&gt;
&lt;li&gt;Samsung, SK hynix, and Micron have all redirected capacity toward high-bandwidth memory (HBM) and advanced DDR5 for AI accelerators. Micron's entire 2026 HBM output is reportedly already committed, which leaves less fab capacity for ordinary server DRAM.&lt;/li&gt;
&lt;li&gt;Hard drives are reportedly sold out for the year, and analysts expect tight allocation and elevated pricing to persist into 2027.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Server memory and storage are not a rounding error in a machine's bill of materials, they are most of it. When DRAM nearly doubles year over year and high-capacity drives are on allocation, the cost of building a new server rises sharply, and that 575% jump on Hetzner's memory add-ons back in April suddenly makes sense. A host running on thin margins cannot absorb that. It passes through.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Hetzner shows it first
&lt;/h2&gt;

&lt;p&gt;It is tempting to read this as a Hetzner problem and conclude that the hyperscalers are safer. The opposite is closer to the truth. Hetzner is a leading indicator, not an outlier.&lt;/p&gt;

&lt;p&gt;Hetzner sells close to cost. It buys hardware, racks it, and rents it with little margin to cushion a shock, so when component prices spike, the increase reaches customers in weeks. AWS, Google Cloud, and Azure buy in enormous volume on long contracts, sit on far higher margins, and wrap everything in committed-use discounts and multi-year enterprise agreements. That hides a cost shock for a while. It does not prevent it. The same DRAM and the same drives go into their racks too, and the bill arrives later, as quietly worse renewal terms, thinner discounts, pricier memory-optimized instances, and instance families that stop getting cheaper the way they used to. If a near-cost provider just went up 99%, the providers selling the same silicon at a markup are not immune. They are just slower to show it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is Hetzner still worth it?
&lt;/h2&gt;

&lt;p&gt;Mostly, yes. Even after this increase, Hetzner remains dramatically cheaper than the hyperscalers for raw compute and bandwidth. A doubling of a number that started at a fraction of the AWS equivalent is still a fraction of the AWS equivalent. To put numbers on it, here is a comparably shaped box (around 2 vCPU and 8 GB) across three providers:&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%2Fr7ihue94hlmu5xwjkp7b.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%2Fr7ihue94hlmu5xwjkp7b.png" alt=" " width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even after more than doubling, the Hetzner box is still cheaper than the same shape on DigitalOcean and well under AWS on demand. What changed is the size of the gap: before June 15 that machine was roughly a quarter of the AWS price, and now it is closer to two thirds. The discount is real, it is just no longer the runaway it used to be, and a committed-use plan on AWS would narrow it further. The moat shrank, it did not close, and the egress story (where Hetzner includes generous traffic and the hyperscalers bill roughly $0.09 per GB after a small allowance) did not change at all. For a bandwidth-heavy service, that egress line can still dwarf the compute difference.&lt;/p&gt;

&lt;p&gt;So the answer is not to rage-quit to a more expensive provider out of spite. It is to re-run the numbers you have probably not looked at since you set them, because the assumptions underneath them just moved.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to actually do about it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Protect your grandfathered machines.&lt;/strong&gt; Existing servers keep their old price until you reorder or rescale. That means a casual resize now reprices the whole machine at the new rate. Before you bump a server up a tier, check what it will cost after the change, not before. If you were about to tear down and recreate something, that is now a price increase you are choosing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat memory as the cost center it has become.&lt;/strong&gt; The line item that exploded is RAM. Audit your over-provisioned instances, the ones sized for a peak that never comes, because every spare gigabyte is now meaningfully more expensive. Right-sizing memory was always good hygiene; this is the quarter it pays for itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Look hard at ARM.&lt;/strong&gt; Hetzner's ARM line took a third of the increase the x86 lines did. If your stack runs on ARM, or could with a rebuild of your images, you dodge a large part of this and usually get better price-performance anyway. The same is true on the hyperscalers with Graviton and equivalents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-run your cost model and budget for hardware inflation everywhere.&lt;/strong&gt; This is not contained to one host or one quarter. Price your colo refresh, your cloud renewals, and yes, the RAM in your next batch of laptops, against a market that analysts expect to stay tight into 2027. If you build cost models, raise the memory and storage line and leave it raised.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not over-correct.&lt;/strong&gt; Migrating providers has its own large costs in engineering time and risk. The right move for most teams is to measure, right-size, and renegotiate, not to flee. Panic migrations during a price shock are how you trade a 99% line-item increase for a 100% project you did not need.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The bigger signal
&lt;/h2&gt;

&lt;p&gt;Strip away the Hetzner specifics and here is what is left: the AI build-out is now large enough to move the price of the components every other computing workload depends on. You do not have to train a model, run inference, or ship a single AI feature to pay for the boom. If your service needs memory and disks, and all of them do, you are bidding for the same supply that the AI data centers are buying 70% of, and they are bidding harder.&lt;/p&gt;

&lt;p&gt;Hetzner is just the first invoice to say so out loud. The rest will follow in their own time and their own quieter language. Plan your next year of infrastructure spend as if memory is expensive and scarce, because for the foreseeable future, it is.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>linux</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Neon vs Supabase Free Tiers: We Benchmarked Both So You Don't Have To</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Mon, 22 Jun 2026 18:56:30 +0000</pubDate>
      <link>https://dev.to/devopsdaily/neon-vs-supabase-free-tiers-we-benchmarked-both-so-you-dont-have-to-hic</link>
      <guid>https://dev.to/devopsdaily/neon-vs-supabase-free-tiers-we-benchmarked-both-so-you-dont-have-to-hic</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-free-tier-benchmarks" rel="noopener noreferrer"&gt;DevOps Daily&lt;/a&gt;. The charts below are static snapshots; the live, interactive versions and the open source benchmark harness are on the original.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pick any "Neon vs Supabase" thread on the internet and you will find the same spec-sheet ping pong: one side quotes storage limits, the other quotes monthly active users, and nobody has actually timed anything. Both platforms hand out free Postgres, both claim to be fast, and both free tiers have sharp edges that only show up when you run real operations against them.&lt;/p&gt;

&lt;p&gt;So we ran real operations against them. 320 timed samples across nine operation types, both platforms in the same AWS region (eu-central-1, Frankfurt), measured from a client VM in the same metro so network distance could not put a thumb on the scale. Every raw sample, the harness that produced it, and a live dashboard are public, so you can check the math or rerun the whole thing yourself: explore the &lt;a href="https://postgres-benchmarks.devops-daily.com/" rel="noopener noreferrer"&gt;live results dashboard&lt;/a&gt; or read the harness at &lt;a href="https://github.com/The-DevOps-Daily/serverless-postgres-benchmarks" rel="noopener noreferrer"&gt;The-DevOps-Daily/serverless-postgres-benchmarks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the free tier piece. Paid-tier operations (read replicas, compute resizing, Supabase branching) get their own article once those runs land.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Query latency is a tie.&lt;/strong&gt; Every connection path on both platforms lands at a 25 to 30 ms median for a full connect + TLS + auth + query cycle from a same-region client. Do not pick either platform for single-query speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project creation is closer than you think.&lt;/strong&gt; Neon: 5.7 s median to a queryable database. Supabase: 7.4 s. Both have outliers above 11 s.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The idle behavior is the real difference.&lt;/strong&gt; Neon free databases scale to zero after 5 minutes and wake automatically in about 570 ms. Supabase free projects pause after 7 days of inactivity and stay down until you log in and restore them by hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branching only exists on one side.&lt;/strong&gt; Neon free includes copy-on-write branches that arrive carrying the parent's data, queryable in 2.2 s. Supabase branching requires a paid plan and starts without data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Networking will surprise you.&lt;/strong&gt; Supabase free-tier direct connections are IPv6-only. From an IPv4 client (most CI runners, many VPSes, most home networks) you must use their pooler, and the TLS chain is signed by Supabase's own CA.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How we measured
&lt;/h2&gt;

&lt;p&gt;The harness is a small TypeScript runner that drives each platform's management API plus a regular &lt;code&gt;pg&lt;/code&gt; connection. The rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both platforms in &lt;strong&gt;aws eu-central-1&lt;/strong&gt;, measured from a 2 vCPU VM in Frankfurt (1 to 2 ms from both).&lt;/li&gt;
&lt;li&gt;Every operation runs repeatedly: 50 runs for latency paths, 20 for project creation and cold starts, 10 for branching. Reports use &lt;strong&gt;median and p95&lt;/strong&gt;, never single runs.&lt;/li&gt;
&lt;li&gt;Latency samples use a &lt;strong&gt;cold connection each time&lt;/strong&gt;: connect, TLS handshake, auth, &lt;code&gt;select 1&lt;/code&gt;, disconnect. That is what a serverless function pays per invocation without a warm pool, and it is a fairer test than hammering one warm session.&lt;/li&gt;
&lt;li&gt;Every resource is created fresh, named &lt;code&gt;bench-*&lt;/code&gt;, and deleted after the run.&lt;/li&gt;
&lt;li&gt;Raw samples are committed to the repo with region, plan, and client metadata. The numbers below link to data, not to memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Free plans on both sides, as of June 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query latency: stop arguing about it
&lt;/h2&gt;

&lt;p&gt;Five different connection paths, 50 cold-connection cycles each:&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%2Fg5a92rsl877ae16l02ic.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%2Fg5a92rsl877ae16l02ic.png" alt="Query latency: cold connection, select 1 (median, 50 runs each)" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Query latency: cold connection, select 1 (median, 50 runs each) — &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-free-tier-benchmarks" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is a 5 ms spread across ten thousand-ish kilometers of marketing. At equal network distance, the free tiers are latency-equivalent for a single query. The spread between the fastest and slowest path on the &lt;em&gt;same&lt;/em&gt; platform is bigger than the spread between platforms.&lt;/p&gt;

&lt;p&gt;The percentile view makes the tails visible too. Every one of the 250 samples, ranked:&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%2Fpbckvvekalt1cdr43oey.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%2Fpbckvvekalt1cdr43oey.png" alt="Query latency percentiles (50 cold connections per path)" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Query latency percentiles (50 cold connections per path) — &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-free-tier-benchmarks" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What this means in practice: latency should not be on your decision sheet at all. Region placement matters about 10x more than vendor choice, because every millisecond of client-to-region distance gets added to each of these numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project creation: both are fast now
&lt;/h2&gt;

&lt;p&gt;Time from the management API call to the first successful &lt;code&gt;select 1&lt;/code&gt;, 20 runs each:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Median&lt;/th&gt;
&lt;th&gt;p95&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Neon&lt;/td&gt;
&lt;td&gt;5.7 s&lt;/td&gt;
&lt;td&gt;8.8 s&lt;/td&gt;
&lt;td&gt;3.5 s to 13.6 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supabase&lt;/td&gt;
&lt;td&gt;7.4 s&lt;/td&gt;
&lt;td&gt;11.8 s&lt;/td&gt;
&lt;td&gt;6.5 s to 11.9 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things stood out. First, both are genuinely fast: a complete, queryable Postgres in single-digit seconds. Supabase used to take minutes to provision a project; that reputation is outdated. Second, neither is consistent: Neon's fastest run was 3.5 s and its slowest 13.6 s, nearly a 4x spread, so do not build automation that assumes the median.&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%2Ffyqblcvf4maauzza7cf2.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%2Ffyqblcvf4maauzza7cf2.png" alt="Project creation: API call to first successful query" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Project creation: API call to first successful query — &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-free-tier-benchmarks" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If your workflow creates databases programmatically (per-tenant databases, ephemeral test environments, agent-driven tooling), both free tiers can technically do it, but the caps differ wildly: Neon allows up to 100 projects on the free plan, Supabase allows 2 active projects per organization. For anything that creates databases in a loop, that single line of the spec sheet decides for you before any benchmark does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idle behavior: a nap versus a coma
&lt;/h2&gt;

&lt;p&gt;This is the section that should actually drive your decision for side projects, and it is the one spec sheets describe worst.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Neon&lt;/strong&gt; free compute always scales to zero after 5 minutes of inactivity. You cannot turn that off on the free plan. The flip side: it wakes automatically on the next connection. We suspended and woke a database 20 times:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wake query (first query against suspended compute): &lt;strong&gt;568 ms median, 1.06 s p95&lt;/strong&gt;, worst case 1.55 s.&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%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmak0hkwqz5qwqrpedtvl.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%2Fmak0hkwqz5qwqrpedtvl.png" alt="Neon cold start: first query against suspended compute" width="799" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Neon cold start: first query against suspended compute — &lt;a href="https://devops-daily.com/posts/neon-vs-supabase-free-tier-benchmarks" rel="noopener noreferrer"&gt;interactive version on DevOps Daily&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Neon's docs say cold starts are "typically a few hundred milliseconds" with 500 ms as the usual ceiling. Measured from a same-region client, reality is a bit slower: our median sat just above their typical ceiling, and the p95 crossed a full second. Not bad, just not quite the brochure. For a hobby app behind a page load, an occasional extra half second on the first request after a quiet stretch is invisible. For a latency-sensitive API that gets sparse traffic, it is a real consideration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supabase&lt;/strong&gt; free compute never naps; your project runs a dedicated instance around the clock, so there are no cold starts at all. Instead, after 7 days without activity, the whole project is &lt;strong&gt;paused&lt;/strong&gt;. A paused project does not wake on connection. You log into the dashboard and restore it manually, which takes on the order of minutes, and until you do, every connection fails outright.&lt;/p&gt;

&lt;p&gt;So the trade is: Neon costs you ~570 ms after every 5 quiet minutes but never needs you; Supabase costs you nothing while active but a manual rescue if you ever leave it alone for a week. For a demo you show twice a month, that 7-day pause is the difference between "works when the customer clicks" and "dead link in your portfolio."&lt;/p&gt;

&lt;h2&gt;
  
  
  Branching: only one of them brings the data
&lt;/h2&gt;

&lt;p&gt;Database branching is the headline feature of serverless Postgres, and on free tiers it is not a comparison, because only Neon has it there. We branched a project carrying 100,000 seeded rows, 10 times:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writable branch, parent's full dataset included, queryable: &lt;strong&gt;2.2 s median, 3.2 s p95&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One honest nuance the marketing skips: the copy-on-write storage operation itself is effectively instant, but a usable branch needs its own compute endpoint, and provisioning that is where the 2 seconds go. "Branches in milliseconds" is true at the storage layer and false at the connection string. What you actually get is a full writable copy of a database, with data, in about the time it takes to read this sentence, which is still excellent and still the same primitive that makes per-PR preview databases and agent test loops practical.&lt;/p&gt;

&lt;p&gt;Supabase shipped Branching 2.0 in 2025 (Git optional, branch from the dashboard or API), but it requires a paid plan, each branch bills as its own compute, and branches copy schema and config without production data. We will measure it properly in the paid-tier article.&lt;/p&gt;

&lt;h2&gt;
  
  
  The networking fine print nobody tells you
&lt;/h2&gt;

&lt;p&gt;Three things we hit while building the harness that will absolutely hit you too:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Supabase free direct connections are IPv6-only.&lt;/strong&gt; &lt;code&gt;db.&amp;lt;ref&amp;gt;.supabase.co&lt;/code&gt; has no A record, only AAAA. If your client is IPv4-only, and that includes most CI runners, many cloud VMs by default, and most home ISPs, you cannot reach the direct host at all. You connect through Supavisor instead: session mode on port 5432, transaction mode on 6543. Both pooler paths carry IPv4. (A dedicated IPv4 address for direct connections exists as a paid add-on.) Neon's endpoints answer on both stacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Supabase pooler hostname varies per project.&lt;/strong&gt; Our first project landed on &lt;code&gt;aws-1-eu-central-1.pooler.supabase.com&lt;/code&gt; while the documented examples reference &lt;code&gt;aws-0-...&lt;/code&gt;. Both exist. Do not hardcode the pooler host from a tutorial; read your project's connection info from the dashboard or the Management API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Supabase database TLS chains to Supabase's own CA.&lt;/strong&gt; The certs are not signed by a public authority, so a client that verifies certificates (which should be all of them) needs &lt;a href="https://supabase.com/docs/guides/platform/ssl-enforcement" rel="noopener noreferrer"&gt;their root certificate&lt;/a&gt;. And if you use node-postgres, there is a trap inside the trap: when your connection string contains &lt;code&gt;sslmode=require&lt;/code&gt;, &lt;code&gt;pg&lt;/code&gt; silently ignores the &lt;code&gt;ssl&lt;/code&gt; options object where you so carefully loaded that CA file, and verification fails with &lt;code&gt;self-signed certificate in certificate chain&lt;/code&gt;. Drop &lt;code&gt;sslmode&lt;/code&gt; from the URL and configure TLS exclusively through the &lt;code&gt;ssl&lt;/code&gt; option. That one cost us an hour; it is yours for free.&lt;/p&gt;

&lt;p&gt;None of these are dealbreakers. All three are the kind of thing you want to know on a Tuesday afternoon rather than discover during a Friday deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The limits, side by side
&lt;/h2&gt;

&lt;p&gt;The measured behavior above, plus the caps that matter, as of June 2026:&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;Neon free&lt;/th&gt;
&lt;th&gt;Supabase free&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Database storage&lt;/td&gt;
&lt;td&gt;0.5 GB per project&lt;/td&gt;
&lt;td&gt;500 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Projects&lt;/td&gt;
&lt;td&gt;up to 100&lt;/td&gt;
&lt;td&gt;2 active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compute&lt;/td&gt;
&lt;td&gt;100 CU-hours/project/month, autoscaling to 2 CU&lt;/td&gt;
&lt;td&gt;dedicated Nano instance, always on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idle behavior&lt;/td&gt;
&lt;td&gt;scales to zero after 5 min, auto-wakes in ~570 ms&lt;/td&gt;
&lt;td&gt;project pauses after 7 days, manual restore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branching&lt;/td&gt;
&lt;td&gt;10 branches/project, data included, ~2.2 s&lt;/td&gt;
&lt;td&gt;not available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restore window&lt;/td&gt;
&lt;td&gt;6 hours&lt;/td&gt;
&lt;td&gt;none (daily backups start on Pro)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extras&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Auth (50K MAU), storage (1 GB), edge functions (500K), realtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Direct connection&lt;/td&gt;
&lt;td&gt;IPv4 + IPv6&lt;/td&gt;
&lt;td&gt;IPv6 only (pooler for IPv4)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Which free tier should you pick?
&lt;/h2&gt;

&lt;p&gt;The latency tie makes this refreshingly simple: pick on shape, not speed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick Neon's free tier when the database is the product.&lt;/strong&gt; Side projects with irregular traffic (auto-wake beats manual restore), anything that needs many databases (100 projects vs 2), CI and preview environments (branching with data is free-tier-exclusive), and agent or automation workflows that create and destroy databases programmatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick Supabase's free tier when you are shipping an app, not a database.&lt;/strong&gt; The bundled auth, storage, realtime, and auto-generated APIs replace three or four other free tiers you would otherwise stitch together, and 50K monthly active users of free auth is genuinely hard to beat. Just put a calendar reminder somewhere if the project might go quiet for a week.&lt;/p&gt;

&lt;p&gt;One forward-looking note: in June 2026 Neon announced S3-compatible object storage that branches with the database, serverless functions, and an AI gateway, all marked coming soon. If those ship, the bundled-stack gap narrows; we will rerun this comparison when they do.&lt;/p&gt;

&lt;p&gt;And if you are still torn, the structural differences run deeper than the free tiers: we maintain a full &lt;a href="https://devops-daily.com/comparisons/neon-vs-supabase" rel="noopener noreferrer"&gt;Neon vs Supabase comparison&lt;/a&gt; covering architecture, pricing models, PITR, and the paid features side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the series goes next
&lt;/h2&gt;

&lt;p&gt;This post is part one. The free tiers are where you start, but the interesting differences show up when money and production traffic enter the picture, so we kept going:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devops-daily.com/posts/neon-vs-supabase-operational-benchmarks" rel="noopener noreferrer"&gt;Part two: operational benchmarks&lt;/a&gt; times the operations that page you: compute resize (and its downtime), branching at scale, read replicas, point-in-time restore, and 200-connection stampedes, on the paid tiers.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devops-daily.com/posts/neon-vs-supabase-scaling-costs" rel="noopener noreferrer"&gt;Part three: scaling costs&lt;/a&gt; prices the same application through five growth stages on both platforms, with an open source cost model you can rerun on your own workload.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Run it yourself
&lt;/h2&gt;

&lt;p&gt;Every number in this post is the median of committed raw samples. The &lt;a href="https://postgres-benchmarks.devops-daily.com/" rel="noopener noreferrer"&gt;live dashboard&lt;/a&gt; tracks every benchmark session (the charts there update as new runs land, including a latency-over-time view), and the harness behind it is about 600 lines of TypeScript: &lt;a href="https://github.com/The-DevOps-Daily/serverless-postgres-benchmarks" rel="noopener noreferrer"&gt;The-DevOps-Daily/serverless-postgres-benchmarks&lt;/a&gt;. Bring your own API keys, &lt;code&gt;npm run bench&lt;/code&gt;, and argue with our data instead of someone's vibes.&lt;/p&gt;

&lt;p&gt;These benchmarks are fully open source, and contributions are welcome. If you spot something off in the methodology, know a fairer way to measure an operation, or get different numbers from another region or another month, open an issue or send a pull request to &lt;a href="https://github.com/The-DevOps-Daily/serverless-postgres-benchmarks" rel="noopener noreferrer"&gt;the repo&lt;/a&gt;. The whole point of publishing the harness and every raw sample is that this comparison can be checked, challenged, and improved by anyone, instead of being remembered as a vibe.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>neon</category>
      <category>supabase</category>
      <category>database</category>
    </item>
    <item>
      <title>Secrets Management Best Practices with HashiCorp Vault</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Mon, 22 Jun 2026 10:55:34 +0000</pubDate>
      <link>https://dev.to/devopsdaily/secrets-management-best-practices-with-hashicorp-vault-1pd9</link>
      <guid>https://dev.to/devopsdaily/secrets-management-best-practices-with-hashicorp-vault-1pd9</guid>
      <description>&lt;p&gt;A database password leaks. Maybe it was committed to a private repo three years ago, maybe it sat in a CI log, maybe a contractor copied it into a Slack DM. You do not know, because that password has been valid the entire time and nobody rotated it. Now you are in an incident channel at 2am trying to figure out the blast radius of a credential that every service, every old laptop, and every backup job has used since 2023.&lt;/p&gt;

&lt;p&gt;This is the problem HashiCorp Vault solves, and it is not the problem most teams use it for. Most teams install Vault, run it in dev mode, dump a pile of static key-value secrets into it, and call it done. That gives you an encrypted password store with a nicer API. Useful, but it leaves the worst part untouched: secrets that live forever and that no human can fully account for.&lt;/p&gt;

&lt;p&gt;The real win with Vault is making secrets short-lived and generated on demand, so a leak has an expiry date measured in hours instead of years. This post shows how to run Vault for that: a production server that survives reboots, machine authentication that does not depend on root tokens, dynamic database credentials, and encryption as a service. Every command here is one you can run.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Never run &lt;code&gt;vault server -dev&lt;/code&gt; for anything real. It is in-memory and unsealed, so a restart wipes every secret.&lt;/li&gt;
&lt;li&gt;Use auto-unseal (AWS KMS, GCP KMS, or another Vault) so a reboot does not need five humans with key shares.&lt;/li&gt;
&lt;li&gt;Authenticate machines with &lt;strong&gt;AppRole&lt;/strong&gt;, not long-lived root or service tokens.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;dynamic secrets&lt;/strong&gt; for databases. Vault creates a unique DB user per request with a short TTL and deletes it when the lease ends.&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;transit engine&lt;/strong&gt; for encryption as a service so your apps never touch the encryption keys.&lt;/li&gt;
&lt;li&gt;Write least-privilege policies, turn on the audit log, and revoke leases when something goes wrong.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Linux host (or VM) where you can install the Vault binary&lt;/li&gt;
&lt;li&gt;Vault 1.15 or newer (&lt;code&gt;vault version&lt;/code&gt; to check)&lt;/li&gt;
&lt;li&gt;A PostgreSQL database you can point Vault at for the dynamic secrets section&lt;/li&gt;
&lt;li&gt;An AWS account with a KMS key if you want auto-unseal (optional but recommended)&lt;/li&gt;
&lt;li&gt;Basic comfort with the command line and HCL config files&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stop running Vault in dev mode
&lt;/h2&gt;

&lt;p&gt;Dev mode is the trap. You run one command and get a working Vault:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault server &lt;span class="nt"&gt;-dev&lt;/span&gt;
&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;==&amp;gt; Vault server configuration:
             Api Address: http://127.0.0.1:8200
                     Cgo: disabled
         Cluster Address: https://127.0.0.1:8201
              Listener 1: tcp (addr: "127.0.0.1:8200", tls: "disabled")
               Log Level: info
                   Mlock: supported: true, enabled: false
           Recovery Mode: false
                 Storage: inmem

WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read that warning. &lt;code&gt;Storage: inmem&lt;/code&gt; means every secret lives in RAM and disappears on restart. &lt;code&gt;tls: disabled&lt;/code&gt; means traffic is plaintext. It starts unsealed, so anyone who reaches port 8200 owns it. Dev mode is for trying commands on your laptop, nothing else.&lt;/p&gt;

&lt;p&gt;A production server needs three things dev mode skips: persistent storage, TLS, and a seal. Here is a real &lt;code&gt;config.hcl&lt;/code&gt; using integrated Raft storage and AWS KMS auto-unseal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/vault.d/vault.hcl&lt;/span&gt;
&lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="s2"&gt;"raft"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;path&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/opt/vault/data"&lt;/span&gt;
  &lt;span class="nx"&gt;node_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vault-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;listener&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;address&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.0.0.0:8200"&lt;/span&gt;
  &lt;span class="nx"&gt;tls_cert_file&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/opt/vault/tls/vault.crt"&lt;/span&gt;
  &lt;span class="nx"&gt;tls_key_file&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/opt/vault/tls/vault.key"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Auto-unseal: Vault asks KMS to decrypt its root key on boot.&lt;/span&gt;
&lt;span class="c1"&gt;# No more gathering humans with key shares after every restart.&lt;/span&gt;
&lt;span class="nx"&gt;seal&lt;/span&gt; &lt;span class="s2"&gt;"awskms"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
  &lt;span class="nx"&gt;kms_key_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:kms:us-east-1:111122223333:key/abc-12345"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;api_addr&lt;/span&gt;     &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://vault-1.internal:8200"&lt;/span&gt;
&lt;span class="nx"&gt;cluster_addr&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://vault-1.internal:8201"&lt;/span&gt;
&lt;span class="nx"&gt;ui&lt;/span&gt;           &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start it and initialize once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault server &lt;span class="nt"&gt;-config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/etc/vault.d/vault.hcl &amp;amp;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;VAULT_ADDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://vault-1.internal:8200"&lt;/span&gt;
vault operator init &lt;span class="nt"&gt;-recovery-shares&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="nt"&gt;-recovery-threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3
&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;Recovery Key 1: vR2k9... (give to a different person than key 2)
Recovery Key 2: 8Lp4m...
Recovery Key 3: qW7nZ...
Recovery Key 4: 3xF8t...
Recovery Key 5: hT1bY...

Initial Root Token: hvs.CAESIJ...

Success! Vault is initialized

Recovery key initialized with 5 key shares and a key threshold of 3.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because of auto-unseal you get &lt;strong&gt;recovery keys&lt;/strong&gt; instead of unseal keys. Vault unseals itself on boot using KMS, and the recovery keys are only for emergencies like regenerating the root token. Split them across different people and store them offline. Never keep all of them in one place.&lt;/p&gt;

&lt;p&gt;Now use that root token once to set up authentication and policies, then throw it away. Root tokens are for break-glass moments, not daily use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault login hvs.CAESIJ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you ever see this, your Vault restarted and could not reach its seal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vault kv get secret/payments/stripe
Error making API request.
URL: GET https://vault-1.internal:8200/v1/secret/data/payments/stripe
Code: 503. Errors:
* Vault is sealed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sealed Vault answers nothing. That is the whole point. Auto-unseal exists so this state heals itself instead of paging you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authenticate machines with AppRole, not tokens
&lt;/h2&gt;

&lt;p&gt;A common mistake: generate a long-lived token, paste it into an app's environment, and forget it exists. Now you have the same forever-credential problem one layer up. If that token leaks, it works until someone notices.&lt;/p&gt;

&lt;p&gt;For machines, use &lt;strong&gt;AppRole&lt;/strong&gt;. The app proves its identity with a &lt;code&gt;role_id&lt;/code&gt; (think username, not very secret) and a &lt;code&gt;secret_id&lt;/code&gt; (think password, short-lived and delivered separately), and gets back a token scoped to exactly what it needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault auth &lt;span class="nb"&gt;enable &lt;/span&gt;approle

&lt;span class="c"&gt;# Create a role for the payments service.&lt;/span&gt;
vault write auth/approle/role/payments-api &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;token_policies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"payments-api"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;token_ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1h &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;token_max_ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4h &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;secret_id_ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;24h &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;secret_id_num_uses&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1

&lt;span class="c"&gt;# role_id is stable and tied to the role.&lt;/span&gt;
vault &lt;span class="nb"&gt;read &lt;/span&gt;auth/approle/role/payments-api/role-id
&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;Key        Value
---        -----
role_id    7b1c4e2a-9f3d-4a8e-b6c1-2d5f8e0a1b3c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;secret_id&lt;/code&gt; is the part that needs care. Generate it just before the app starts and hand it over once. With &lt;code&gt;secret_id_num_uses=1&lt;/code&gt; it works exactly one time, so a leaked &lt;code&gt;secret_id&lt;/code&gt; in a log is already useless.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault write &lt;span class="nt"&gt;-f&lt;/span&gt; auth/approle/role/payments-api/secret-id
&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;Key                   Value
---                   -----
secret_id             d8a3...e91f
secret_id_accessor    4c2b...77a0
secret_id_ttl         24h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app logs in with both and gets a short-lived token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault write auth/approle/login &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;role_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"7b1c4e2a-9f3d-4a8e-b6c1-2d5f8e0a1b3c"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;secret_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"d8a3...e91f"&lt;/span&gt;
&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;Key                  Value
---                  -----
token                hvs.CAESI...
token_duration       1h
token_renewable      true
token_policies       ["default" "payments-api"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That token dies in an hour unless the app renews it. The pattern that delivers the &lt;code&gt;secret_id&lt;/code&gt; securely (a sidecar, a cloud instance identity, or Vault Agent) is its own topic, but the rule is simple: the &lt;code&gt;role_id&lt;/code&gt; can live in config, the &lt;code&gt;secret_id&lt;/code&gt; should be freshly minted and single-use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic database credentials
&lt;/h2&gt;

&lt;p&gt;This is the feature that changes how you think about secrets. Instead of one shared database password that every service knows, Vault creates a brand new database user for each request, with a short TTL, and deletes it when the lease expires.&lt;/p&gt;

&lt;p&gt;Enable the database engine and point it at PostgreSQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault secrets &lt;span class="nb"&gt;enable &lt;/span&gt;database

vault write database/config/orders-db &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;plugin_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"postgresql-database-plugin"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;allowed_roles&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"orders-readonly"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;connection_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"postgresql://{{username}}:{{password}}@db.internal:5432/orders?sslmode=require"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"vault-admin"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ROOT_DB_PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;vault-admin&lt;/code&gt; account is the only static credential, and it is a privileged account Vault uses to create and drop other users. Now define a role that says what a generated user is allowed to do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault write database/roles/orders-readonly &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;db_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"orders-db"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;creation_statements&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"CREATE ROLE &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;{{name}}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
      GRANT SELECT ON ALL TABLES IN SCHEMA public TO &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;{{name}}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;default_ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1h"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;max_ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"24h"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask for credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault &lt;span class="nb"&gt;read &lt;/span&gt;database/creds/orders-readonly
&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;Key                Value
---                -----
lease_id           database/creds/orders-readonly/Qm9iY...
lease_duration     1h
lease_renewable    true
password           A1a-9Zx2Kp4Lq7Rt0Vn3
username           v-approle-orders-rea-x7Qd2bN9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;username&lt;/code&gt; did not exist a second ago. Run the command again and you get a different user with a different password. Each service instance, each request if you want, gets its own credentials. When the lease ends, Vault runs the revocation statement and the user is gone from PostgreSQL.&lt;/p&gt;

&lt;p&gt;Here is why this matters in numbers. A static password sits valid until a human rotates it, which in practice means months or years. A dynamic credential with a one-hour TTL is useless to an attacker an hour after it leaks.&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%2Fre4wn1vhsjgp4wf4q6cd.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%2Fre4wn1vhsjgp4wf4q6cd.png" alt="How long a leaked credential stays valid" width="799" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The shrink in exposure window is the entire reason to run Vault. If you take one thing from this post, make it this section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encryption as a service with the transit engine
&lt;/h2&gt;

&lt;p&gt;Sometimes you do not want to store a secret, you want to encrypt application data: a customer's tax ID, a token, a column in your database. The wrong move is to ship an AES key to every app and hope nobody loses it. The transit engine keeps the key inside Vault and exposes encrypt and decrypt operations. Your app sends plaintext and gets ciphertext back. It never sees the key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault secrets &lt;span class="nb"&gt;enable &lt;/span&gt;transit
vault write &lt;span class="nt"&gt;-f&lt;/span&gt; transit/keys/orders-pii
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Encrypt some data (transit takes base64 input):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault write transit/encrypt/orders-pii &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;plaintext&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"4111-1111-1111-1111"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&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;Key            Value
---            -----
ciphertext     vault:v1:8SDd4HCQ9p7Hf2bxN0kZ...
key_version    1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store &lt;code&gt;vault:v1:8SDd...&lt;/code&gt; in your database. To read it back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault write transit/decrypt/orders-pii &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;ciphertext&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"vault:v1:8SDd4HCQ9p7Hf2bxN0kZ..."&lt;/span&gt;
&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;Key          Value
---          -----
plaintext    NDExMS0xMTExLTExMTEtMTExMQ==
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Base64-decode that and you are back to the card number. The &lt;code&gt;v1&lt;/code&gt; prefix is the key version, which means you can rotate the key with &lt;code&gt;vault write -f transit/keys/orders-pii/rotate&lt;/code&gt; and old ciphertext still decrypts while new writes use the fresh key. No key ever leaves Vault, so an app compromise leaks data the app could already see, not the key that protects all of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Least-privilege policies and the audit log
&lt;/h2&gt;

&lt;p&gt;Tokens are only as safe as the policy attached to them. The &lt;code&gt;payments-api&lt;/code&gt; policy referenced earlier should grant exactly what the service needs and nothing more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# payments-api.hcl&lt;/span&gt;
&lt;span class="c1"&gt;# Read dynamic DB creds for the orders database.&lt;/span&gt;
&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="s2"&gt;"database/creds/orders-readonly"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"read"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Encrypt and decrypt PII, but not manage or export the key.&lt;/span&gt;
&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="s2"&gt;"transit/encrypt/orders-pii"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="s2"&gt;"transit/decrypt/orders-pii"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault policy write payments-api payments-api.hcl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what is missing. No &lt;code&gt;database/creds/orders-admin&lt;/code&gt;, no &lt;code&gt;transit/keys/*&lt;/code&gt; management, no wildcard paths. If the payments token leaks, the attacker can read orders and decrypt PII for an hour, and that is the ceiling. When a request asks for something outside the policy, Vault refuses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vault read database/creds/orders-admin
Error reading database/creds/orders-admin: Error making API request.
URL: GET https://vault-1.internal:8200/v1/database/creds/orders-admin
Code: 403. Errors:
* 1 error occurred:
    * permission denied
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turn on the audit log before you put anything real in Vault. It records every request and response (secrets are HMAC'd, not stored in clear) so you can answer "who read this secret and when" during an incident:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault audit &lt;span class="nb"&gt;enable &lt;/span&gt;file &lt;span class="nv"&gt;file_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/log/vault/audit.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when you do have an incident, dynamic secrets give you a clean kill switch. Revoke every credential a database role ever issued in one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault lease revoke &lt;span class="nt"&gt;-prefix&lt;/span&gt; database/creds/orders-readonly
&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;All revocation operations queued successfully!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every dynamic user that role created gets dropped from the database. Try doing that with a shared password that lives in forty places.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go next
&lt;/h2&gt;

&lt;p&gt;You now have the shape of a real Vault setup: a sealed, persistent server; AppRole for machines; dynamic database credentials; transit for encryption; tight policies; and an audit trail. The static KV store is still there when you need it, but it should be the exception, not the default.&lt;/p&gt;

&lt;p&gt;Concrete next steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Replace one static database password with a dynamic role this week.&lt;/strong&gt; Pick a low-risk read-only service and cut over. Seeing credentials expire on their own is what makes the model click.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stand up a 3-node Raft cluster&lt;/strong&gt;, not a single server. One Vault node is a single point of failure for every secret you own. Run &lt;code&gt;vault operator raft list-peers&lt;/code&gt; to confirm the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy Vault Agent&lt;/strong&gt; to handle AppRole login and token renewal so your apps read a rendered file or env var instead of calling the Vault API directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set short TTLs and test revocation.&lt;/strong&gt; Run &lt;code&gt;vault lease revoke -prefix&lt;/code&gt; against a staging role and confirm the users vanish from your database. Know the command works before you need it at 2am.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ship the audit log to your SIEM&lt;/strong&gt; so secret access shows up next to the rest of your security telemetry.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Start with step one. Turning a single forever-password into a one-hour credential is the smallest change that removes the largest class of secret leaks you have.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>security</category>
      <category>linux</category>
    </item>
    <item>
      <title>10 GitHub Repositories That Will Actually Teach You DevOps in 2026</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Tue, 05 May 2026 18:11:07 +0000</pubDate>
      <link>https://dev.to/devopsdaily/10-github-repositories-that-will-actually-teach-you-devops-in-2026-266e</link>
      <guid>https://dev.to/devopsdaily/10-github-repositories-that-will-actually-teach-you-devops-in-2026-266e</guid>
      <description>&lt;p&gt;There are roughly a thousand "top DevOps repos" listicles, and most of them are the same five awesome-lists in a different order. The problem with awesome-lists is that they are link directories. They tell you where to look, not what to do. If you want to actually get better at DevOps, you need a different shape of repo: ones with exercises, opinionated learning paths, hands-on demos, and source you can read and learn from.&lt;/p&gt;

&lt;p&gt;So here are ten GitHub repositories that have moved real engineers from "I have heard of Kubernetes" to "I run it in production." We will start with the one we maintain on this site, then walk through the rest in order of star count, with notes on who each one is for and how to get the most out of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR
&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;Repo&lt;/th&gt;
&lt;th&gt;Stars&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/The-DevOps-Daily/devops-daily" rel="noopener noreferrer"&gt;The-DevOps-Daily/devops-daily&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;1k+&lt;/td&gt;
&lt;td&gt;Tutorials, exercises, and quizzes across the stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/nilbuild/developer-roadmap" rel="noopener noreferrer"&gt;nilbuild/developer-roadmap&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;354k&lt;/td&gt;
&lt;td&gt;Visual roadmap to plan your learning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/bregman-arie/devops-exercises" rel="noopener noreferrer"&gt;bregman-arie/devops-exercises&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;82k&lt;/td&gt;
&lt;td&gt;Interview prep and practice questions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/kelseyhightower/kubernetes-the-hard-way" rel="noopener noreferrer"&gt;kelseyhightower/kubernetes-the-hard-way&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;48k&lt;/td&gt;
&lt;td&gt;Building Kubernetes from scratch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/MichaelCade/90DaysOfDevOps" rel="noopener noreferrer"&gt;MichaelCade/90DaysOfDevOps&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;29k&lt;/td&gt;
&lt;td&gt;A structured 90-day plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/milanm/DevOps-Roadmap" rel="noopener noreferrer"&gt;milanm/DevOps-Roadmap&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;19k&lt;/td&gt;
&lt;td&gt;Roadmap with linked study resources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/ramitsurana/awesome-kubernetes" rel="noopener noreferrer"&gt;ramitsurana/awesome-kubernetes&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;16k&lt;/td&gt;
&lt;td&gt;Curated Kubernetes deep-dive material&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/dastergon/awesome-sre" rel="noopener noreferrer"&gt;dastergon/awesome-sre&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;13k&lt;/td&gt;
&lt;td&gt;SRE-specific reading list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/stefanprodan/podinfo" rel="noopener noreferrer"&gt;stefanprodan/podinfo&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;6k&lt;/td&gt;
&lt;td&gt;A real microservice to deploy with GitOps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/wmariuss/awesome-devops" rel="noopener noreferrer"&gt;wmariuss/awesome-devops&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;4k&lt;/td&gt;
&lt;td&gt;Broader DevOps tooling and practices&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Star counts are pulled fresh from the GitHub API as of May 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The-DevOps-Daily/devops-daily
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/The-DevOps-Daily/devops-daily" rel="noopener noreferrer"&gt;github.com/The-DevOps-Daily/devops-daily&lt;/a&gt;. the source for everything you read on this site, fully open source.&lt;/p&gt;

&lt;p&gt;We did not put ourselves at the top because we own the site. We put ourselves at the top because the way the repo is structured is a fast loop: every blog post, exercise, quiz, flashcard, checklist, and interview question is a markdown or JSON file you can read, fork, and PR into. If you find a typo, a broken command, or an outdated CLI flag, you can fix it. If you have a better explanation of how kubelet eviction works, you can add a card to the relevant flashcard deck.&lt;/p&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browse the &lt;code&gt;content/&lt;/code&gt; directory. Pick a topic you want to get better at and run through the exercise.&lt;/li&gt;
&lt;li&gt;Use the quizzes for spaced retrieval. Repeat until you stop getting things wrong.&lt;/li&gt;
&lt;li&gt;Submit a PR when you find something to improve. The maintainers (us) review fast and merge most of the time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for engineers who learn by doing, contributing, and seeing the underlying source of every lesson.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. nilbuild/developer-roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/nilbuild/developer-roadmap" rel="noopener noreferrer"&gt;github.com/nilbuild/developer-roadmap&lt;/a&gt;. 354k stars. Originally &lt;code&gt;kamranahmedse/developer-roadmap&lt;/code&gt;, now under the &lt;code&gt;nilbuild&lt;/code&gt; org. The DevOps roadmap is at &lt;a href="https://roadmap.sh/devops" rel="noopener noreferrer"&gt;roadmap.sh/devops&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a visual map of the skills, tools, and concepts that make up a DevOps career. It is the single best document on the internet for answering "what should I learn next?" without reinventing your own learning plan from scratch.&lt;/p&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the DevOps roadmap. Identify the area you are weakest in.&lt;/li&gt;
&lt;li&gt;Click any node to get a short explanation, links, and a checklist.&lt;/li&gt;
&lt;li&gt;Mark items as you go. The site keeps your progress in localStorage if you do not sign up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for people who feel scattered and want a single picture of the field.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. bregman-arie/devops-exercises
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/bregman-arie/devops-exercises" rel="noopener noreferrer"&gt;github.com/bregman-arie/devops-exercises&lt;/a&gt;. 82k stars. Maintained by Arie Bregman, ex-Red Hat.&lt;/p&gt;

&lt;p&gt;This repository is the reason a lot of engineers passed their DevOps interviews. It is hundreds of practical questions and exercises across Linux, Jenkins, AWS, SRE, Prometheus, Docker, Python, Ansible, Git, Kubernetes, Terraform, OpenStack, SQL, NoSQL, Azure, GCP, and more. Each topic has a mix of explanation questions ("What is X and when do you use it?") and hands-on exercises ("Write the Terraform module that does X").&lt;/p&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick a topic. Try to answer the questions out loud or in writing without looking at the answers.&lt;/li&gt;
&lt;li&gt;Star the ones you got wrong. Come back to them in a week.&lt;/li&gt;
&lt;li&gt;Use it as a barometer. If you can answer most of the Kubernetes section without help, you know your Kubernetes is solid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for interview preparation and finding gaps in your knowledge.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. kelseyhightower/kubernetes-the-hard-way
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/kelseyhightower/kubernetes-the-hard-way" rel="noopener noreferrer"&gt;github.com/kelseyhightower/kubernetes-the-hard-way&lt;/a&gt;. 48k stars. The repo description is honest: "Bootstrap Kubernetes the hard way. No scripts."&lt;/p&gt;

&lt;p&gt;If you have only ever used &lt;code&gt;gcloud container clusters create&lt;/code&gt; or &lt;code&gt;eksctl&lt;/code&gt;, you have used Kubernetes. You have not learned it. This walkthrough has you stand up a control plane and worker nodes by hand, with TLS certificates you generated yourself, etcd you configured yourself, and a kubelet you registered yourself.&lt;/p&gt;

&lt;p&gt;It is also a primary reason Kelsey Hightower has the reputation he has, which is its own kind of education.&lt;/p&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Block out a weekend. The full walkthrough takes 6 to 10 hours the first time.&lt;/li&gt;
&lt;li&gt;Do not copy commands. Type them. Read what they do before you run them.&lt;/li&gt;
&lt;li&gt;When something breaks (and it will), debug it. That is the entire point.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for engineers who want a deep mental model of Kubernetes internals.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. MichaelCade/90DaysOfDevOps
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/MichaelCade/90DaysOfDevOps" rel="noopener noreferrer"&gt;github.com/MichaelCade/90DaysOfDevOps&lt;/a&gt;. 29k stars. Three years of community-curated 90-day plans.&lt;/p&gt;

&lt;p&gt;This started as one engineer's public learning project: 90 days, one DevOps topic per day, write what you learned. It exploded, and is now a structured tour through Linux, networking, programming, containers, Kubernetes, IaC, observability, databases, and serverless across three different yearly cohorts. The format is one folder per day with notes, diagrams, and links.&lt;/p&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat it as a TV series, not a textbook. Watch one "episode" a day for 90 days.&lt;/li&gt;
&lt;li&gt;Skip topics you already know. Spend extra time on the ones that feel uncomfortable.&lt;/li&gt;
&lt;li&gt;Read previous cohorts' notes when you finish a day. The 2022, 2023, and 2024 versions cover slightly different angles on the same material.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for engineers early in their career who want a forced curriculum.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. milanm/DevOps-Roadmap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/milanm/DevOps-Roadmap" rel="noopener noreferrer"&gt;github.com/milanm/DevOps-Roadmap&lt;/a&gt;. 19k stars. A different style of roadmap from #2.&lt;/p&gt;

&lt;p&gt;Where the nilbuild roadmap is a visual node graph, this one is a long markdown document with curated links, books, courses, and YouTube videos for every step of the path. It is heavier on resources, lighter on the conceptual map.&lt;/p&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the introduction. Identify which "phase" of the roadmap you are at.&lt;/li&gt;
&lt;li&gt;Pick one resource per concept. Do not read all five linked resources for the same topic. Pick the format that matches how you learn best.&lt;/li&gt;
&lt;li&gt;Use the prompts at the end of each section as a checklist before moving on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for self-taught engineers building their own curriculum.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. ramitsurana/awesome-kubernetes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ramitsurana/awesome-kubernetes" rel="noopener noreferrer"&gt;github.com/ramitsurana/awesome-kubernetes&lt;/a&gt;. 16k stars. The most thorough Kubernetes-specific awesome-list.&lt;/p&gt;

&lt;p&gt;If your day job is Kubernetes-heavy and you want to specialize, this is the link directory you want. It has sections for everything: storage, networking, monitoring, security, multi-cluster, GitOps, service mesh, FinOps. Each link is annotated.&lt;/p&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bookmark the page. Use it as a research starting point when you need to evaluate tools in a category.&lt;/li&gt;
&lt;li&gt;Watch the commit log. New tools get added regularly, so it doubles as a "what is happening in Kubernetes" feed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for Kubernetes-track engineers and platform teams researching tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. dastergon/awesome-sre
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/dastergon/awesome-sre" rel="noopener noreferrer"&gt;github.com/dastergon/awesome-sre&lt;/a&gt;. 13k stars. The SRE-flavored cousin.&lt;/p&gt;

&lt;p&gt;DevOps and SRE overlap, but the SRE side weights toward reliability theory, incident response, observability, and the social engineering of running production systems. This repo is the curated reading list for that side: books (Google's SRE book, Charity Majors' work), papers, postmortems, blog posts, conference talks, training courses.&lt;/p&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read at least one published postmortem a week. The "Postmortems" section is gold.&lt;/li&gt;
&lt;li&gt;The conference talks list is more useful than most paid SRE courses.&lt;/li&gt;
&lt;li&gt;Pair it with &lt;code&gt;kelseyhightower/kubernetes-the-hard-way&lt;/code&gt; if your SRE work is on a Kubernetes platform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for engineers moving into SRE or platform-engineering roles.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. stefanprodan/podinfo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/stefanprodan/podinfo" rel="noopener noreferrer"&gt;github.com/stefanprodan/podinfo&lt;/a&gt;. 6k stars. A small Go web app that exists to be deployed.&lt;/p&gt;

&lt;p&gt;This one is different from the others. podinfo is not a learning resource in the read-and-take-notes sense. It is a real microservice (Go, REST + gRPC, metrics, tracing, health checks) that is purpose-built to be the demo target in tutorials. It is what every Flux, Argo CD, Linkerd, Istio, and Cilium tutorial uses when they need a service to deploy. If you want to actually try a GitOps tool end-to-end, you build the platform, point it at podinfo's helm chart, and ship.&lt;/p&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stand up a kind or k3d cluster locally.&lt;/li&gt;
&lt;li&gt;Install Flux or Argo CD and point it at the podinfo chart.&lt;/li&gt;
&lt;li&gt;Roll out a canary. Add Linkerd. Add Prometheus. Each thing you add lets you exercise a different platform skill on a service that already works.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for engineers who learn by deploying, not reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. wmariuss/awesome-devops
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/wmariuss/awesome-devops" rel="noopener noreferrer"&gt;github.com/wmariuss/awesome-devops&lt;/a&gt;. 4k stars. Smaller than &lt;code&gt;awesome-kubernetes&lt;/code&gt;, broader in scope.&lt;/p&gt;

&lt;p&gt;This is the everything-DevOps awesome list: chaos engineering, configuration management, container orchestration, log management, monitoring, package management, secret management, service discovery. The size of the list is approachable, which is its main strength. You can scroll the whole thing in 15 minutes and have a real mental map of the DevOps tooling landscape.&lt;/p&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the section headings before clicking any links. The taxonomy itself is a learning aid.&lt;/li&gt;
&lt;li&gt;When evaluating a new category of tool (say, you have to pick a secret manager), use this as your starting set rather than Googling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for engineers who want a manageable map of the whole DevOps tools world.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Actually Use a List Like This
&lt;/h2&gt;

&lt;p&gt;Lists are starting points, not learning plans. The mistake people make is to star all ten repos and never come back. Avoid that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick exactly one starting repo today.&lt;/strong&gt; If you have no plan, start with #2 (the roadmap) to get one. If you have a plan, start with #4 (kubernetes-the-hard-way) to deepen it. If you are interview-prepping, start with #3 (devops-exercises).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block calendar time.&lt;/strong&gt; "I will learn DevOps in my spare time" does not work. "I will spend Thursdays from 7 to 9 PM on the kubernetes-the-hard-way walkthrough" works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build something.&lt;/strong&gt; Pick one of the awesome-list categories you do not understand (say, "service mesh") and use podinfo (#9) plus a tool from the list to build a working setup. You will learn more in two hours of building than two weeks of reading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teach what you learned.&lt;/strong&gt; Write a blog post. Submit a PR to #1 with a flashcard you made. Give a brown-bag at work. Teaching is the fastest way to find the gaps in what you thought you knew.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bookmark this page and come back when you finish one repo. The list is not going anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Awesome-lists are link directories&lt;/strong&gt;, not learning plans. Pair them with hands-on repos like #1, #4, and #9.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Star counts are not the same as quality&lt;/strong&gt;, but they are a decent first filter. Anything above 5k stars in this space has been read by enough people to be roughly trustworthy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The single best learning loop is read → build → teach.&lt;/strong&gt; Most engineers do step one, skip step two, and never reach step three. The repos in this list are picked to support all three.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start one. Finish one.&lt;/strong&gt; Do not collect ten tabs and never close any of them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contribute back.&lt;/strong&gt; Every repo in this list takes PRs. Even small ones (typo fixes, broken-link fixes) count. They also get you GitHub history that future employers can see.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we missed a repo you think belongs here, &lt;a href="https://github.com/The-DevOps-Daily/devops-daily/issues" rel="noopener noreferrer"&gt;open an issue on our repo&lt;/a&gt; and tell us which one. We update this list when something deserves to be on it.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>opensource</category>
      <category>learning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Claude Code Hidden Features You Probably Missed</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Wed, 01 Apr 2026 17:21:58 +0000</pubDate>
      <link>https://dev.to/devopsdaily/claude-code-hidden-features-you-probably-missed-3ej0</link>
      <guid>https://dev.to/devopsdaily/claude-code-hidden-features-you-probably-missed-3ej0</guid>
      <description>&lt;p&gt;Most people use Claude Code to write code, fix bugs, and maybe generate a commit message. That's fine, but you're leaving a lot on the table.&lt;/p&gt;

&lt;p&gt;Boris Cherny, the creator of Claude Code, recently shared a &lt;a href="https://x.com/bcherny/status/2038454336355999749" rel="noopener noreferrer"&gt;thread on X&lt;/a&gt; about features that even daily users tend to overlook. Some of these genuinely changed how I work. Here's a rundown of the ones worth knowing about.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR
&lt;/h2&gt;

&lt;p&gt;Claude Code has mobile sessions, automated scheduling, voice input, parallel agents, git worktrees, hooks, and a browser extension. Most people use about 20% of what it can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Move Your Session Anywhere with /teleport
&lt;/h2&gt;

&lt;p&gt;You can start a session on your laptop and pick it up on your phone. Or move it to the web. The &lt;code&gt;/teleport&lt;/code&gt; command transfers your full session context between devices.&lt;/p&gt;

&lt;p&gt;The reverse also works. If you're reviewing something on your phone during a commute, you can &lt;code&gt;/teleport&lt;/code&gt; it back to your terminal when you sit down.&lt;/p&gt;

&lt;p&gt;There's also &lt;code&gt;/remote-control&lt;/code&gt; which lets you connect to a running session from another device without transferring it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# On your laptop&lt;/span&gt;
/teleport

&lt;span class="c"&gt;# On your phone or web - enter the code to pick up the session&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when you kick off a long-running task on your workstation and want to check progress from your phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate Repetitive Tasks with /loop and /schedule
&lt;/h2&gt;

&lt;p&gt;This one is a genuine workflow changer. You can tell Claude Code to run a task on a recurring schedule for up to a week.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Review PRs every 30 minutes&lt;/span&gt;
/loop 30m review open PRs and post comments

&lt;span class="c"&gt;# Run a health check every hour&lt;/span&gt;
/schedule every 1h check &lt;span class="k"&gt;if &lt;/span&gt;the staging environment is healthy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think about what you do repeatedly: reviewing PRs, checking CI status, monitoring deployments, updating dependencies. You can automate all of it without writing a single script.&lt;/p&gt;

&lt;p&gt;Some practical examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review all open PRs every morning at 9 AM&lt;/li&gt;
&lt;li&gt;Monitor a Slack channel for feedback and create GitHub issues&lt;/li&gt;
&lt;li&gt;Run your test suite after every push and report failures&lt;/li&gt;
&lt;li&gt;Check for dependency updates weekly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hooks for Deterministic Automation
&lt;/h2&gt;

&lt;p&gt;Hooks let you run code at specific points in Claude Code's lifecycle. Unlike the AI-driven &lt;code&gt;/loop&lt;/code&gt; command, hooks are deterministic - they always run the same way.&lt;/p&gt;

&lt;p&gt;You configure them in your settings and they fire on events like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session start&lt;/strong&gt; - set up your environment, load context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Before bash commands&lt;/strong&gt; - validate or log commands before execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On permission requests&lt;/strong&gt; - auto-approve specific patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous operation&lt;/strong&gt; - keep Claude running without manual intervention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is powerful for teams. You can enforce standards (like running linters before every commit) without relying on each engineer to remember.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Worktrees for Parallel Sessions
&lt;/h2&gt;

&lt;p&gt;If you've ever wanted Claude to work on two different branches at the same time, worktrees make this possible. Each session gets its own isolated copy of the repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start a session in a worktree&lt;/span&gt;
claude &lt;span class="nt"&gt;--worktree&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this matters: you can have Claude refactoring module A while simultaneously building feature B. Neither session interferes with the other.&lt;/p&gt;

&lt;p&gt;This pairs well with &lt;code&gt;/batch&lt;/code&gt;, which fans out work across dozens of parallel agents. Need to update 50 files? &lt;code&gt;/batch&lt;/code&gt; can process them concurrently instead of one at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Voice Input with /voice
&lt;/h2&gt;

&lt;p&gt;You can dictate to Claude instead of typing. This sounds gimmicky until you try it for longer explanations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/voice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's particularly useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explaining complex requirements ("I need a migration that handles both the old and new schema formats, with a rollback path if...")&lt;/li&gt;
&lt;li&gt;Code reviews ("Look at the authentication flow in this PR and tell me if...")&lt;/li&gt;
&lt;li&gt;Brainstorming ("What's the best way to structure this API given these constraints...")&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typing detailed prompts takes time. Talking is faster for anything longer than a few sentences.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Chrome Extension for Frontend Work
&lt;/h2&gt;

&lt;p&gt;Claude Code has a Chrome extension that lets the AI see what your app looks like in the browser. Instead of describing UI bugs, Claude can verify its own output visually.&lt;/p&gt;

&lt;p&gt;This closes the feedback loop for frontend work. Claude makes a change, checks the browser, adjusts if something looks off. You stop being the human screenshot tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  /branch and --fork-session for Experiments
&lt;/h2&gt;

&lt;p&gt;Want to try two different approaches to the same problem? &lt;code&gt;/branch&lt;/code&gt; creates a copy of your current session so you can explore a different path without losing your progress.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fork the current session&lt;/span&gt;
/branch

&lt;span class="c"&gt;# Or fork when starting&lt;/span&gt;
claude &lt;span class="nt"&gt;--fork-session&lt;/span&gt; &amp;lt;session-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is like git branches but for your AI conversation. Try approach A in one branch, approach B in another, then pick the winner.&lt;/p&gt;

&lt;h2&gt;
  
  
  /btw for Side Questions
&lt;/h2&gt;

&lt;p&gt;When Claude is working on a long task, you might have an unrelated question. Instead of interrupting the main task, &lt;code&gt;/btw&lt;/code&gt; lets you ask a side question.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/btw what&lt;span class="s1"&gt;'s the difference between SIGTERM and SIGKILL?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude answers your side question and goes right back to what it was doing. No context switching, no lost progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  --bare for SDK Speed
&lt;/h2&gt;

&lt;p&gt;If you're using Claude Code in scripts or CI pipelines, the &lt;code&gt;--bare&lt;/code&gt; flag skips loading plugins and extra features, making startup up to 10x faster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--bare&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"generate a migration for adding user roles"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters when you're calling Claude from automation scripts where every second counts.&lt;/p&gt;

&lt;h2&gt;
  
  
  --add-dir for Multi-Repo Work
&lt;/h2&gt;

&lt;p&gt;Working across multiple repositories? You can give Claude access to all of them in a single session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--add-dir&lt;/span&gt; ~/projects/api &lt;span class="nt"&gt;--add-dir&lt;/span&gt; ~/projects/frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Claude can see your API schema and your frontend code at the same time. No more copying types between repos or explaining your API structure manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Agents with --agent
&lt;/h2&gt;

&lt;p&gt;You can create custom agent configurations with their own system prompts and tool permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--agent&lt;/span&gt; reviewer    &lt;span class="c"&gt;# Uses your custom reviewer agent config&lt;/span&gt;
claude &lt;span class="nt"&gt;--agent&lt;/span&gt; deployer    &lt;span class="c"&gt;# Uses your custom deployer agent config&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define these in your &lt;code&gt;.claude/agents/&lt;/code&gt; directory. Each agent can have different instructions, different tool access, and different behaviors. A code reviewer agent doesn't need write access. A deployment agent doesn't need to browse the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Means for DevOps
&lt;/h2&gt;

&lt;p&gt;These features shift Claude Code from "AI code assistant" to "AI DevOps team member." The combination of scheduling, hooks, parallel sessions, and multi-repo access means you can automate workflows that previously required custom tooling.&lt;/p&gt;

&lt;p&gt;Here's a realistic DevOps setup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;/schedule&lt;/code&gt; reviews all PRs every morning&lt;/li&gt;
&lt;li&gt;Hooks enforce linting and security scanning on every session&lt;/li&gt;
&lt;li&gt;Worktrees let you debug production while shipping features&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--add-dir&lt;/code&gt; gives Claude access to your infra and app repos simultaneously&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/loop&lt;/code&gt; monitors your staging environment and alerts you on issues&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key insight from Boris's thread: "There is no one right way to use Claude Code." The tool is intentionally flexible. Experiment with these features and build the workflow that fits your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;If you haven't updated Claude Code recently, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Many of these features are recent additions. The mobile app, scheduling, and hooks in particular have been added in the last few months.&lt;/p&gt;

&lt;p&gt;For more DevOps tools and guides, check out our &lt;a href="https://dev.to/exercises"&gt;exercises&lt;/a&gt; and &lt;a href="https://dev.to/quizzes"&gt;quizzes&lt;/a&gt; to sharpen your skills.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was inspired by &lt;a href="https://x.com/bcherny/status/2038454336355999749" rel="noopener noreferrer"&gt;Boris Cherny's thread on X&lt;/a&gt;. Boris is the creator of Claude Code at Anthropic.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>devops</category>
      <category>linux</category>
    </item>
    <item>
      <title>🎄 Advent of DevOps: 25 Days to Level Up Your DevOps Game!</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Sun, 30 Nov 2025 22:00:00 +0000</pubDate>
      <link>https://dev.to/devopsdaily/advent-of-devops-25-days-to-level-up-your-devops-game-2fb5</link>
      <guid>https://dev.to/devopsdaily/advent-of-devops-25-days-to-level-up-your-devops-game-2fb5</guid>
      <description>&lt;p&gt;Hey DevOps enthusiasts! 👋&lt;/p&gt;

&lt;p&gt;Remember how exciting advent calendars were as a kid? Each day bringing a new surprise behind those little doors? Well, we're bringing that same excitement to the DevOps world, but instead of chocolate (sorry! 🍫), you're getting something even better: &lt;strong&gt;real-world DevOps skills that will make you a better engineer&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎁 What is Advent of DevOps?
&lt;/h2&gt;

&lt;p&gt;Think "Advent of Code" meets real-world DevOps challenges. Starting December 1st, we're releasing &lt;strong&gt;25 daily hands-on challenges&lt;/strong&gt; that cover everything you need to know to thrive in modern DevOps environments.&lt;/p&gt;

&lt;p&gt;Each day unlocks a new practical challenge focusing on tools and techniques you'll actually use in production. No theory-heavy lectures, no boring slides—just pure, hands-on learning that you can apply immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 What's Inside?
&lt;/h2&gt;

&lt;p&gt;Here's a taste of what you'll tackle over 25 days:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐳 &lt;strong&gt;Containerization &amp;amp; Orchestration&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;⚙️ &lt;strong&gt;CI/CD &amp;amp; Automation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🏗️ &lt;strong&gt;Infrastructure as Code&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🔒 &lt;strong&gt;Security &amp;amp; Observability&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;☁️ &lt;strong&gt;Cloud &amp;amp; Scaling&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💡 Why Join?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🎯 Real-World Skills&lt;/strong&gt;: Every challenge is based on actual scenarios you'll face in production&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📈 Progressive Learning&lt;/strong&gt;: Start easy, level up gradually. Whether you're a beginner or seasoned pro, there's something for you&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎮 Fun &amp;amp; Engaging&lt;/strong&gt;: Gamified progress tracking makes learning addictive (in a good way!)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🌟 Community-Driven&lt;/strong&gt;: Share solutions, learn from others, and grow together&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⏰ Learn at Your Pace&lt;/strong&gt;: Can't keep up daily? No problem! All challenges remain available year-round&lt;/p&gt;

&lt;h2&gt;
  
  
  🎄 How It Works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick Your Challenge&lt;/strong&gt;: Start with Day 1 or jump to what interests you most&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get Hands-On&lt;/strong&gt;: Each challenge includes clear tasks, starter code, and success criteria&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build &amp;amp; Learn&lt;/strong&gt;: Complete the challenge at your own pace&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share &amp;amp; Celebrate&lt;/strong&gt;: Post your wins and solutions with the community&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level Up&lt;/strong&gt;: Review reference solutions and explanations to deepen your understanding&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each challenge includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Clear task description&lt;/li&gt;
&lt;li&gt;🎯 Success criteria&lt;/li&gt;
&lt;li&gt;🔧 Starter code (when applicable)&lt;/li&gt;
&lt;li&gt;💡 Solution &amp;amp; explanation&lt;/li&gt;
&lt;li&gt;🔗 Additional resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🌟 Join the Community
&lt;/h2&gt;

&lt;p&gt;This isn't just about solo learning—it's about growing together! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Share your progress:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow us on X/Twitter: &lt;a href="https://x.com/thedevopsdaily" rel="noopener noreferrer"&gt;@thedevopsdaily&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use hashtag: &lt;strong&gt;#AdventOfDevOps&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Share on LinkedIn, dev.to, wherever you hang out!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Contribute:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Found a cool solution? Share it!&lt;/li&gt;
&lt;li&gt;Have ideas for challenges? We're open-source!&lt;/li&gt;
&lt;li&gt;Check out our &lt;a href="https://github.com/The-DevOps-Daily/devops-daily" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; and contribute&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎯 Ready to Start?
&lt;/h2&gt;

&lt;p&gt;Don't wait for December 1st to check it out—head over to the page now and get familiar with what's coming:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://devops-daily.com/advent-of-devops" rel="noopener noreferrer"&gt;devops-daily.com/advent-of-devops&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mark your calendar 📅, set your reminders ⏰, and get ready to transform your DevOps skills one day at a time!&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 Who Should Join?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DevOps Engineers&lt;/strong&gt; looking to sharpen their skills&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developers&lt;/strong&gt; wanting to understand the ops side better&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System Administrators&lt;/strong&gt; transitioning to DevOps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Students &amp;amp; Career Changers&lt;/strong&gt; building practical experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anyone&lt;/strong&gt; curious about modern infrastructure practices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No gatekeeping here, if you're interested in DevOps, you're welcome! 🙌&lt;/p&gt;

&lt;h2&gt;
  
  
  🎊 Let's Make This December Special
&lt;/h2&gt;

&lt;p&gt;Learning doesn't have to be boring. It doesn't have to be stressful. And it definitely doesn't have to be lonely.&lt;/p&gt;

&lt;p&gt;This December, join hundreds (thousands?) of DevOps practitioners around the world in leveling up together. One challenge at a time, one skill at a time, one day at a time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;See you on December 1st! 🎄✨&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;P.S. - Can't wait? Start exploring the challenges now at &lt;a href="https://devops-daily.com/advent-of-devops" rel="noopener noreferrer"&gt;devops-daily.com/advent-of-devops&lt;/a&gt;. They're already live and ready for early birds! 🐦&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.P.S. - This is completely free, open-source, and community-driven. No paywalls, no upsells, just pure learning. If you find value, give us a star on &lt;a href="https://github.com/The-DevOps-Daily/devops-daily" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; and spread the word! ⭐&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Follow DevOps Daily:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐦 X/Twitter: &lt;a href="https://x.com/thedevopsdaily" rel="noopener noreferrer"&gt;@thedevopsdaily&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 GitHub: &lt;a href="https://github.com/The-DevOps-Daily/devops-daily" rel="noopener noreferrer"&gt;The-DevOps-Daily/devops-daily&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 Website: &lt;a href="https://devops-daily.com" rel="noopener noreferrer"&gt;devops-daily.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy DevOps-ing! 🚀&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>beginners</category>
      <category>adventofcode</category>
    </item>
    <item>
      <title>Building a DDoS Attack Simulator to Understand Defense Strategies</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Fri, 21 Nov 2025 09:53:22 +0000</pubDate>
      <link>https://dev.to/devopsdaily/building-a-ddos-attack-simulator-to-understand-defense-strategies-lg4</link>
      <guid>https://dev.to/devopsdaily/building-a-ddos-attack-simulator-to-understand-defense-strategies-lg4</guid>
      <description>&lt;p&gt;I created an educational content piece for DevOps Daily and realized something: most explanations of DDoS attacks are either too abstract or too technical. We talk about "request floods" and "mitigation strategies," but it's hard to visualize what's actually happening.&lt;/p&gt;

&lt;p&gt;So I built an interactive simulator to help bridge that gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Learning About DDoS 📚
&lt;/h2&gt;

&lt;p&gt;When you're reading about DDoS protection, you see phrases like "distributes load across multiple servers" or "rate limiting prevents abuse." But what does that actually mean when thousands of requests are hitting your infrastructure?&lt;/p&gt;

&lt;p&gt;I wanted something that would help people - especially those newer to infrastructure work - actually see these concepts in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Simulator Does 🎮
&lt;/h2&gt;

&lt;p&gt;You can try it here: &lt;a href="https://devops-daily.com/games/ddos-simulator" rel="noopener noreferrer"&gt;devops-daily.com/games/ddos-simulator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It lets you simulate three common attack types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP Flood&lt;/strong&gt; 🌊 - overwhelming with legitimate-looking requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SYN Flood&lt;/strong&gt; 🔄 - exploiting TCP handshake mechanics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UDP Flood&lt;/strong&gt; 📦 - connectionless packet storms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting part is watching how different defense mechanisms respond. You can toggle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Firewall&lt;/strong&gt; 🛡️ - blocks about 30% based on signatures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load Balancer&lt;/strong&gt; ⚖️ - reduces impact by 50%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Rate Limit&lt;/strong&gt; 🚦 - blocks high-frequency traffic&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Learned Building It 💡
&lt;/h2&gt;

&lt;p&gt;A few things became clear while working on this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attack intensity matters less than you'd think.&lt;/strong&gt; The attack type and your defense configuration matter way more. A moderate SYN flood with no defenses is worse than an intense HTTP flood with proper rate limiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single defenses aren't enough.&lt;/strong&gt; This is obvious in theory, but seeing it play out makes it concrete. A firewall alone, or a load balancer alone, only gets you so far.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visualization helps understanding.&lt;/strong&gt; Watching the server health bar drop while packets animate across the screen creates an intuition that documentation doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Might Find This Useful ⚙️
&lt;/h2&gt;

&lt;p&gt;If you're:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learning about infrastructure security&lt;/li&gt;
&lt;li&gt;Trying to explain DDoS concepts to your team&lt;/li&gt;
&lt;li&gt;Deciding what protections to implement&lt;/li&gt;
&lt;li&gt;Just curious how attacks and defenses interact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It might be helpful to play around with it for a bit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next 🚀
&lt;/h2&gt;

&lt;p&gt;I'm planning to add more waves with additional attack vectors and defense mechanisms. Things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application-layer attacks&lt;/li&gt;
&lt;li&gt;CDN protection&lt;/li&gt;
&lt;li&gt;Anycast routing&lt;/li&gt;
&lt;li&gt;More realistic traffic patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have thoughts on what would be useful to include, I'd be interested to hear them.&lt;/p&gt;




&lt;p&gt;The goal here is education, not creating chaos. Understanding how attacks work helps you build better defenses. 🛡️&lt;/p&gt;

&lt;p&gt;If you try it out, let me know what you think or if anything is unclear.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>systemdesign</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Right-Sizing Kubernetes Resources with VPA and Karpenter</title>
      <dc:creator>DevOps Daily</dc:creator>
      <pubDate>Fri, 22 Aug 2025 17:02:04 +0000</pubDate>
      <link>https://dev.to/devopsdaily/right-sizing-kubernetes-resources-with-vpa-and-karpenter-22ah</link>
      <guid>https://dev.to/devopsdaily/right-sizing-kubernetes-resources-with-vpa-and-karpenter-22ah</guid>
      <description>&lt;h2&gt;
  
  
  TLDR
&lt;/h2&gt;

&lt;p&gt;Setting CPU and memory requests too high in Kubernetes wastes money and reduces cluster efficiency. This guide shows you how to identify overprovisioned workloads, use Vertical Pod Autoscaler (VPA) to right-size your pods, and implement Karpenter for smarter node scaling. You'll also learn to monitor costs and validate your improvements with real metrics.&lt;/p&gt;

&lt;p&gt;When you set resource requests too conservatively in Kubernetes, your cluster reserves more capacity than workloads actually need. This leads to underutilized nodes and higher cloud bills. The problem gets worse at scale - imagine 200 pods each requesting 2 CPU cores but only using 200m. That's 400 reserved cores when actual demand is closer to 40 cores.&lt;/p&gt;

&lt;p&gt;The solution involves right-sizing both your pods and nodes. You'll use monitoring data to understand actual usage, apply VPA to adjust pod requests automatically, and leverage Karpenter to provision nodes that match your workload requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you start, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Kubernetes cluster (version 1.20 or higher) with metrics-server installed&lt;/li&gt;
&lt;li&gt;kubectl configured with admin access to your cluster&lt;/li&gt;
&lt;li&gt;Prometheus and Grafana deployed for monitoring (or similar observability stack)&lt;/li&gt;
&lt;li&gt;Basic understanding of Kubernetes resource requests and limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll also need the ability to install cluster-wide components like VPA and Karpenter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying Overprovisioned Workloads
&lt;/h2&gt;

&lt;p&gt;The first step is understanding how your current workloads use resources compared to what they request. You can start with kubectl to get a quick snapshot of resource usage across your cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check current resource usage for all nodes&lt;/span&gt;
kubectl top nodes

&lt;span class="c"&gt;# View pod resource usage across all namespaces&lt;/span&gt;
kubectl top pods &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt; &lt;span class="nt"&gt;--sort-by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cpu

&lt;span class="c"&gt;# Get detailed resource requests vs usage for a specific namespace&lt;/span&gt;
kubectl describe nodes | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; 15 &lt;span class="s2"&gt;"Allocated resources"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands show you the gap between requested and actual resource usage. If you see pods consistently using 50Mi of memory while requesting 1Gi, or using 100m CPU while requesting 1000m, those are prime candidates for right-sizing.&lt;/p&gt;

&lt;p&gt;For deeper analysis, you'll want historical data from Prometheus. Here are some key queries to run in your Grafana dashboard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# CPU utilization percentage (actual usage vs requests)
(rate(container_cpu_usage_seconds_total{container!=""}[5m]) * 100) /
(container_spec_cpu_quota{container!=""} / container_spec_cpu_period{container!=""})

# Memory utilization percentage
(container_memory_working_set_bytes{container!=""} * 100) /
container_spec_memory_limit_bytes{container!=""}

# Top 10 pods with the highest request-to-usage ratio (biggest waste)
topk(10,
  (container_spec_cpu_quota{container!=""} / container_spec_cpu_period{container!=""}) /
  rate(container_cpu_usage_seconds_total{container!=""}[5m])
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run these queries over a 2-week period to account for traffic variations and identify consistent patterns. Workloads running at 10-20% utilization with stable traffic are good candidates for optimization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing and Configuring VPA
&lt;/h2&gt;

&lt;p&gt;Vertical Pod Autoscaler analyzes your workloads and recommends optimal CPU and memory values. Start by installing VPA in your cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone the VPA repository&lt;/span&gt;
git clone https://github.com/kubernetes/autoscaler.git
&lt;span class="nb"&gt;cd &lt;/span&gt;autoscaler/vertical-pod-autoscaler

&lt;span class="c"&gt;# Deploy VPA components&lt;/span&gt;
./hack/vpa-up.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script installs three main components: the VPA recommender (analyzes usage), the updater (applies changes), and the admission controller (validates recommendations).&lt;/p&gt;

&lt;p&gt;Next, create a VPA configuration for a workload you want to optimize. Start with recommendation mode to see suggested values before making changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# vpa-web-service.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VerticalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-service-vpa&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;targetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;apps/v1'&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-service&lt;/span&gt;
  &lt;span class="na"&gt;updatePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;updateMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Off'&lt;/span&gt; &lt;span class="c1"&gt;# Only provide recommendations, don't auto-update&lt;/span&gt;
  &lt;span class="na"&gt;resourcePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;containerPolicies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app&lt;/span&gt;
        &lt;span class="c1"&gt;# Set boundaries to prevent extreme recommendations&lt;/span&gt;
        &lt;span class="na"&gt;maxAllowed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;4Gi'&lt;/span&gt;
        &lt;span class="na"&gt;minAllowed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;100m'&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;128Mi'&lt;/span&gt;
        &lt;span class="na"&gt;controlledResources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cpu'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;memory'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply the VPA configuration and wait for recommendations to generate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; vpa-web-service.yaml

&lt;span class="c"&gt;# Wait a few minutes, then check recommendations&lt;/span&gt;
kubectl describe vpa web-service-vpa &lt;span class="nt"&gt;-n&lt;/span&gt; production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output shows recommended values for CPU and memory under the &lt;code&gt;Status&lt;/code&gt; section. VPA typically suggests values based on the 90th percentile of usage over the past 8 days, which provides a safety buffer while eliminating waste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying VPA Recommendations Safely
&lt;/h2&gt;

&lt;p&gt;Once you have solid recommendations, you can apply them gradually. Start with non-critical workloads and monitor for any issues.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Update your deployment with VPA recommendations&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-service&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-service&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-service&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.21&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;250m'&lt;/span&gt; &lt;span class="c1"&gt;# Reduced from 1000m based on VPA recommendation&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;512Mi'&lt;/span&gt; &lt;span class="c1"&gt;# Reduced from 2Gi based on VPA recommendation&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;500m'&lt;/span&gt; &lt;span class="c1"&gt;# Set limits 2x requests for burst capacity&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1Gi'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After updating requests, monitor your workloads for at least a week. Watch for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increased pod restarts or OOMKilled events&lt;/li&gt;
&lt;li&gt;Higher response times or error rates&lt;/li&gt;
&lt;li&gt;Pods getting evicted under memory pressure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If everything runs smoothly, you can switch VPA to automatic mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Update VPA to automatically apply changes&lt;/span&gt;
kubectl patch vpa web-service-vpa &lt;span class="nt"&gt;-n&lt;/span&gt; production &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'merge'&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"spec":{"updatePolicy":{"updateMode":"Auto"}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Auto mode, VPA will restart pods when it detects they need different resource allocations. Make sure you have proper PodDisruptionBudgets in place to maintain availability during updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Karpenter for Node Optimization
&lt;/h2&gt;

&lt;p&gt;While VPA optimizes individual pods, Karpenter optimizes your entire node infrastructure. Instead of fixed node groups, Karpenter provisions nodes dynamically based on your workload requirements.&lt;/p&gt;

&lt;p&gt;First, install Karpenter in your cluster. The exact steps depend on your cloud provider, but here's the process for AWS EKS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install Karpenter using Helm&lt;/span&gt;
helm upgrade &lt;span class="nt"&gt;--install&lt;/span&gt; karpenter oci://public.ecr.aws/karpenter/karpenter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--version&lt;/span&gt; &lt;span class="s2"&gt;"0.32.0"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"karpenter"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="s2"&gt;"settings.clusterName=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="s2"&gt;"settings.interruptionQueueName=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a NodePool that defines what types of nodes Karpenter can provision:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# karpenter-nodepool.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karpenter.sh/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePool&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;general-purpose&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Template for nodes Karpenter will create&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;general-purpose&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Instance requirements - Karpenter will pick the best fit&lt;/span&gt;
      &lt;span class="na"&gt;requirements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubernetes.io/arch&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;In&lt;/span&gt;
          &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;amd64'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karpenter.sh/capacity-type&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;In&lt;/span&gt;
          &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;spot'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;on-demand'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Allow both for cost optimization&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node.kubernetes.io/instance-type&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;In&lt;/span&gt;
          &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m6i.large'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m6i.xlarge'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m6i.2xlarge'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;r6i.large'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;r6i.xlarge'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

      &lt;span class="c1"&gt;# Node configuration&lt;/span&gt;
      &lt;span class="na"&gt;nodeClassRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karpenter.k8s.aws/v1beta1&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2NodeClass&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;general-purpose&lt;/span&gt;

      &lt;span class="c1"&gt;# Taints to control which pods can schedule here&lt;/span&gt;
      &lt;span class="na"&gt;taints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karpenter.sh/unschedulable&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;true'&lt;/span&gt;
          &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NoSchedule&lt;/span&gt;

  &lt;span class="c1"&gt;# Scaling and disruption policies&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt; &lt;span class="c1"&gt;# Maximum CPU across all nodes in this pool&lt;/span&gt;
  &lt;span class="na"&gt;disruption&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;consolidationPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;WhenUnderutilized&lt;/span&gt;
    &lt;span class="na"&gt;consolidateAfter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the corresponding EC2NodeClass for AWS-specific configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# karpenter-nodeclass.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karpenter.k8s.aws/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EC2NodeClass&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;general-purpose&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# AMI and instance configuration&lt;/span&gt;
  &lt;span class="na"&gt;amiFamily&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AL2&lt;/span&gt;
  &lt;span class="na"&gt;subnetSelectorTerms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;karpenter.sh/discovery&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${CLUSTER_NAME}'&lt;/span&gt;
  &lt;span class="na"&gt;securityGroupSelectorTerms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;karpenter.sh/discovery&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${CLUSTER_NAME}'&lt;/span&gt;

  &lt;span class="c1"&gt;# Instance store configuration&lt;/span&gt;
  &lt;span class="na"&gt;userData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;#!/bin/bash&lt;/span&gt;
    &lt;span class="s"&gt;/etc/eks/bootstrap.sh ${CLUSTER_NAME}&lt;/span&gt;

  &lt;span class="c1"&gt;# Tags for cost tracking&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Team&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply both configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; karpenter-nodepool.yaml
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; karpenter-nodeclass.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Karpenter will now monitor unschedulable pods and provision appropriately-sized nodes. When you deploy workloads with right-sized resource requests (thanks to VPA), Karpenter will select smaller, more cost-effective instances.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring Cost Impact
&lt;/h2&gt;

&lt;p&gt;To validate your optimizations, you need visibility into resource costs. Kubecost provides detailed insights into how much each workload costs and how much capacity you're wasting.&lt;/p&gt;

&lt;p&gt;Install Kubecost in your cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add the Kubecost Helm repository&lt;/span&gt;
helm repo add kubecost https://kubecost.github.io/cost-analyzer/

&lt;span class="c"&gt;# Install Kubecost with Prometheus integration&lt;/span&gt;
helm &lt;span class="nb"&gt;install &lt;/span&gt;kubecost kubecost/cost-analyzer &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; kubecost &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;kubecostToken&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-token-here"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; prometheus.server.global.external_labels.cluster_id&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access the Kubecost UI by port-forwarding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward &lt;span class="nt"&gt;-n&lt;/span&gt; kubecost deployment/kubecost-cost-analyzer 9090:9090
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Kubecost dashboard, focus on these key metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency scores&lt;/strong&gt;: Shows the percentage of requested resources actually being used&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idle costs&lt;/strong&gt;: Money spent on provisioned but unused resources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right-sizing recommendations&lt;/strong&gt;: Suggestions for adjusting requests and limits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Namespace costs&lt;/strong&gt;: Helps identify which teams or applications drive costs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Track these metrics before and after implementing VPA and Karpenter to quantify your savings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Optimization Example
&lt;/h2&gt;

&lt;p&gt;Let's walk through optimizing a typical microservice deployment. You start with a Node.js API that was conservatively configured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Before optimization&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1000m'&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2Gi'&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2000m'&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;4Gi'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running this workload for two weeks, your monitoring shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Average CPU usage: 150m (15% of requests)&lt;/li&gt;
&lt;li&gt;Average memory usage: 400Mi (20% of requests)&lt;/li&gt;
&lt;li&gt;Peak CPU usage: 300m&lt;/li&gt;
&lt;li&gt;Peak memory usage: 800Mi&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on this data, VPA recommends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# VPA recommendations (with safety buffer)&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;200m'&lt;/span&gt; &lt;span class="c1"&gt;# Covers 99th percentile usage&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;512Mi'&lt;/span&gt; &lt;span class="c1"&gt;# Accounts for memory spikes&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;400m'&lt;/span&gt; &lt;span class="c1"&gt;# 2x requests for burst capacity&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1Gi'&lt;/span&gt; &lt;span class="c1"&gt;# Prevents OOM while allowing growth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cost impact for 20 replicas of this service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Before&lt;/strong&gt;: 20 CPU cores, 40Gi memory requested&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After&lt;/strong&gt;: 4 CPU cores, 10Gi memory requested&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Savings&lt;/strong&gt;: 80% reduction in resource allocation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Karpenter managing nodes, this workload now runs on smaller instances, further reducing costs by eliminating the need for oversized nodes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Resource Quotas and Guardrails
&lt;/h2&gt;

&lt;p&gt;As you roll out right-sizing across your organization, implement quotas to prevent teams from reverting to oversized requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# namespace-quota.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ResourceQuota&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend-team-quota&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;requests.cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;50'&lt;/span&gt; &lt;span class="c1"&gt;# Total CPU requests across all pods&lt;/span&gt;
    &lt;span class="na"&gt;requests.memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;100Gi'&lt;/span&gt; &lt;span class="c1"&gt;# Total memory requests&lt;/span&gt;
    &lt;span class="na"&gt;limits.cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;100'&lt;/span&gt; &lt;span class="c1"&gt;# Total CPU limits&lt;/span&gt;
    &lt;span class="na"&gt;limits.memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;200Gi'&lt;/span&gt; &lt;span class="c1"&gt;# Total memory limits&lt;/span&gt;
    &lt;span class="na"&gt;pods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;100'&lt;/span&gt; &lt;span class="c1"&gt;# Maximum number of pods&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also create LimitRanges to enforce reasonable defaults:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# limit-range.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LimitRange&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pod-limits&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Container&lt;/span&gt;
      &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Default limits if not specified&lt;/span&gt;
        &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;500m'&lt;/span&gt;
        &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1Gi'&lt;/span&gt;
      &lt;span class="na"&gt;defaultRequest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Default requests if not specified&lt;/span&gt;
        &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;100m'&lt;/span&gt;
        &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;256Mi'&lt;/span&gt;
      &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Maximum allowed values&lt;/span&gt;
        &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;4'&lt;/span&gt;
        &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8Gi'&lt;/span&gt;
      &lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Minimum required values&lt;/span&gt;
        &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;50m'&lt;/span&gt;
        &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;64Mi'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These guardrails help maintain optimization gains while giving teams flexibility within reasonable bounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting Common Issues
&lt;/h2&gt;

&lt;p&gt;When implementing VPA and Karpenter, you might encounter some challenges. Here are solutions to the most common problems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VPA recommendations seem too aggressive&lt;/strong&gt;: VPA sometimes suggests very low values during low-traffic periods. Check that your monitoring data covers representative traffic patterns. You can also adjust the VPA algorithm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;resourcePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;containerPolicies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app&lt;/span&gt;
        &lt;span class="na"&gt;controlledValues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RequestsOnly&lt;/span&gt; &lt;span class="c1"&gt;# Only adjust requests, leave limits alone&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Auto&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Karpenter nodes aren't scaling down&lt;/strong&gt;: This usually happens when pods can't be evicted. Check for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Look for pods without PodDisruptionBudgets&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; wide | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; Terminating

&lt;span class="c"&gt;# Check for pods using local storage or host networking&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; yaml | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; 5 hostNetwork

&lt;span class="c"&gt;# Verify PodDisruptionBudgets allow eviction&lt;/span&gt;
kubectl get pdb &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pods getting OOMKilled after VPA optimization&lt;/strong&gt;: This indicates VPA recommendations were too low. Temporarily increase memory requests and check for memory leaks in your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check recent OOM events&lt;/span&gt;
kubectl get events &lt;span class="nt"&gt;--sort-by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.metadata.creationTimestamp | &lt;span class="nb"&gt;grep &lt;/span&gt;OOMKilled

&lt;span class="c"&gt;# Monitor memory usage patterns&lt;/span&gt;
kubectl top pods &lt;span class="nt"&gt;--sort-by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;memory &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can make VPA more conservative by setting higher safety margins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;resourcePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;containerPolicies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app&lt;/span&gt;
        &lt;span class="na"&gt;maxAllowed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2Gi'&lt;/span&gt; &lt;span class="c1"&gt;# Set a reasonable upper bound&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Now that you have VPA and Karpenter working together, consider these additional optimizations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Horizontal Pod Autoscaling&lt;/strong&gt;: Combine with VPA to handle both vertical and horizontal scaling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluster Autoscaler tuning&lt;/strong&gt;: If using multiple node provisioners, configure them to work together&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost alerts&lt;/strong&gt;: Set up notifications when resource costs exceed thresholds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regular reviews&lt;/strong&gt;: Schedule monthly reviews of VPA recommendations and cost reports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also explore more advanced Karpenter features like multiple NodePools for different workload types (CPU-intensive, memory-intensive, GPU workloads) and spot instance strategies for non-critical workloads.&lt;/p&gt;

&lt;p&gt;The key is to treat right-sizing as an ongoing process. As your applications evolve and traffic patterns change, continue monitoring and adjusting to maintain optimal resource utilization.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>cloud</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
