<?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: Syed Ahmer Shah</title>
    <description>The latest articles on DEV Community by Syed Ahmer Shah (@syedahmershah).</description>
    <link>https://dev.to/syedahmershah</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%2F3021645%2Fad95c369-a218-4eb1-9eca-5f628e887906.png</url>
      <title>DEV Community: Syed Ahmer Shah</title>
      <link>https://dev.to/syedahmershah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/syedahmershah"/>
    <language>en</language>
    <item>
      <title>AI Writes Code. It Doesn't Do Engineering.</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Fri, 19 Jun 2026 16:54:48 +0000</pubDate>
      <link>https://dev.to/thesiliconarchitect/ai-writes-code-it-doesnt-do-engineering-2l7b</link>
      <guid>https://dev.to/thesiliconarchitect/ai-writes-code-it-doesnt-do-engineering-2l7b</guid>
      <description>&lt;p&gt;I still remember the first time Copilot finished my function before I did. Felt like magic. Then I shipped that "magic" and it broke prod because it hallucinated an edge case. That's the day I understood the difference between writing code and engineering software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where It Started
&lt;/h2&gt;

&lt;p&gt;AI code tools began as autocomplete on steroids — pattern-matching the next token from billions of GitHub repos. Useful, but dumb. It didn't know &lt;em&gt;why&lt;/em&gt; the code existed, only &lt;em&gt;how&lt;/em&gt; similar code usually looked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where We Are Now
&lt;/h2&gt;

&lt;p&gt;Tools like Claude and Copilot can write entire functions, debug, even architect small systems. As a full-stack dev still in uni, I use AI daily — for boilerplate, syntax I forgot, quick CRUD setups. It's genuinely a force multiplier.&lt;/p&gt;

&lt;p&gt;But speed isn't the same as judgment, and that's where things get shaky.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Catch
&lt;/h2&gt;

&lt;p&gt;Engineering isn't typing syntax. It's:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding &lt;em&gt;why&lt;/em&gt; a system needs to scale a certain way&lt;/li&gt;
&lt;li&gt;Tradeoffs — speed vs cost vs maintainability&lt;/li&gt;
&lt;li&gt;Knowing when a "clean" solution will rot in six months&lt;/li&gt;
&lt;li&gt;Debugging &lt;em&gt;intent&lt;/em&gt;, not just stack traces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI doesn't ask "why are we building this?" It pattern-matches an answer. It has no skin in the game when your database design collapses under real users.&lt;/p&gt;

&lt;p&gt;That tradeoff is worth breaking down properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Upside
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Speed — boilerplate and CRUD setups in seconds&lt;/li&gt;
&lt;li&gt;Fewer dumb typos and syntax errors&lt;/li&gt;
&lt;li&gt;Faster prototyping, faster iteration&lt;/li&gt;
&lt;li&gt;A solid rubber duck that talks back&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Downside
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;False confidence in code nobody actually understood&lt;/li&gt;
&lt;li&gt;Shallow architecture decisions baked in early&lt;/li&gt;
&lt;li&gt;Security blind spots AI won't flag on its own&lt;/li&gt;
&lt;li&gt;Devs who ship working code but never learn &lt;em&gt;why&lt;/em&gt; it works&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where It's Going
&lt;/h2&gt;

&lt;p&gt;AI will write more code, not less. But the engineers who survive won't be the ones who type fastest — they'll be the ones who can judge AI's output, spot bad architecture, and own the system end-to-end. The job is shifting from "write code" to "make decisions AI can't make."&lt;/p&gt;

&lt;p&gt;So learn the fundamentals first. Let AI handle the typing. You handle the thinking — that's the part that still pays.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Find me across the web:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Substack:&lt;/strong&gt; &lt;a href="https://substack.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HackerNoon:&lt;/strong&gt; &lt;a href="https://hackernoon.com/u/syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Substack:&lt;/strong&gt; &lt;a href="https://syedahmershah.substack.com" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YouTube:&lt;/strong&gt; &lt;a href="https://www.youtube.com/@ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instagram:&lt;/strong&gt; &lt;a href="https://www.instagram.com/ahmershahdev/" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TikTok:&lt;/strong&gt; &lt;a href="https://www.tiktok.com/@ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>azure</category>
    </item>
    <item>
      <title>Stop Writing Code AI Agents Can't Read</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Sun, 14 Jun 2026 16:23:02 +0000</pubDate>
      <link>https://dev.to/thesiliconarchitect/stop-writing-code-ai-agents-cant-read-5gdh</link>
      <guid>https://dev.to/thesiliconarchitect/stop-writing-code-ai-agents-cant-read-5gdh</guid>
      <description>&lt;p&gt;okay so this is gonna sound ironic. maybe even a little embarrassing.&lt;/p&gt;

&lt;p&gt;Most of us — and yes, I'm including myself here — use AI tools to &lt;em&gt;write&lt;/em&gt; code every single day. GitHub Copilot, Cursor, Claude, whatever. We let the AI generate entire functions for us. We prompt it to refactor our components, debug our APIs, write our tests.&lt;/p&gt;

&lt;p&gt;And yet, somehow, the code we feed back into those same AI agents is a mess that confuses them completely.&lt;/p&gt;

&lt;p&gt;I noticed this in one of my own projects a few months back. I was building a full-stack app — Node/Express on the backend, React on the frontend — and I asked Cursor to help me trace a bug through three files. The AI just... gave up halfway. It kept referencing variables that didn't exist, confused one function's output with another's, and confidently wrote code that broke things even worse.&lt;/p&gt;

&lt;p&gt;At first I blamed the model. Then I looked at my code.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem Nobody's Talking About
&lt;/h2&gt;

&lt;p&gt;We've spent years writing code for &lt;em&gt;ourselves.&lt;/em&gt; Or for teammates who will hop on a call if something's unclear. Or for future-us who will eventually remember what we meant.&lt;/p&gt;

&lt;p&gt;But AI agents don't have that luxury. They don't ask questions mid-read (well, the good ones try, but there's limits). They parse your code with a context window — a fixed amount of tokens they can "see" at once — and they try to infer everything from that snapshot.&lt;/p&gt;

&lt;p&gt;If your code is ambiguous to a human reading it cold, it's &lt;em&gt;invisible&lt;/em&gt; to an AI agent trying to reason about it.&lt;/p&gt;

&lt;p&gt;As of early 2026, models like Claude Sonnet and GPT-4o have context windows of 200k-450k tokens. That sounds like a lot. But a production codebase? Hundreds of files. Thousands of dependencies. Layers of abstraction. No AI agent sees all of it at once.&lt;/p&gt;

&lt;p&gt;So when you ask Cursor to fix a bug that spans four files, it's reasoning under partial information. Your naming, your structure, your comments — all of that becomes the difference between the agent understanding your intent or hallucinating its way through your codebase.&lt;/p&gt;




&lt;h2&gt;
  
  
  What "AI-Readable" Actually Means
&lt;/h2&gt;

&lt;p&gt;Before I get into the specifics, let me be clear: I'm not saying you should write code &lt;em&gt;for&lt;/em&gt; AI. That's backwards. Good code is good code. What I'm saying is that the things which make code readable to a tired human at 2am are the &lt;em&gt;exact same things&lt;/em&gt; that make code readable to an AI agent working with limited context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-readable code is just... good code. We forgot how to write it.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Sins We're All Guilty Of
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Variable Names That Mean Nothing
&lt;/h3&gt;

&lt;p&gt;This one's embarrassing because we all know better.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// this is what my code actually looked like last year&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is &lt;code&gt;d&lt;/code&gt;? What's &lt;code&gt;u&lt;/code&gt;? What's &lt;code&gt;f&lt;/code&gt;? What the hell is &lt;code&gt;v * m&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;I know what it means. I wrote it. But if I paste this into an AI agent and ask it to add error handling, it has to &lt;em&gt;guess&lt;/em&gt; what everything represents. And it will guess wrong. Or rather — it will guess confidently and write broken code.&lt;/p&gt;

&lt;p&gt;Compare that to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchUserProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;normalizeUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;processedUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;friends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;friend&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;friend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;views&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;friend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now an AI agent can reason about this. It knows &lt;code&gt;normalizeUserData&lt;/code&gt; probably returns something predictable. It knows &lt;code&gt;friends&lt;/code&gt; is an array. It can infer what &lt;code&gt;.views&lt;/code&gt; and &lt;code&gt;.multiplier&lt;/code&gt; are about. Error handling writes itself almost.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Functions Doing Way Too Much
&lt;/h3&gt;

&lt;p&gt;I had a function called &lt;code&gt;handleSubmit&lt;/code&gt; in a React component. It was 180 lines long. It validated form data, made an API call, updated three different state variables, dispatched a Redux action, logged to analytics, and conditionally redirected the user.&lt;/p&gt;

&lt;p&gt;When I asked Claude to help me add loading state to it, the response was almost hilariously wrong. It added &lt;code&gt;setLoading(true)&lt;/code&gt; in four different places because it literally couldn't track the flow.&lt;/p&gt;

&lt;p&gt;The fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before: one 180-line monster&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// after: broken down properly&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validationError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validateFormData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validationError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validationError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;submitUserForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;trackFormSubmission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;redirectToOnboarding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&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;p&gt;Now every sub-function has a single job. An AI agent can understand, modify, or extend any one of them without needing to understand the rest of the 180-line mess.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Magic Numbers Everywhere
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# what does 86400 mean here?
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;time_diff&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;send_reminder_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've seen this in so many codebases. Including ones I wrote. The AI has no idea that &lt;code&gt;86400&lt;/code&gt; is seconds in a day. It might assume it's a timeout value, a database ID limit, a file size — anything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;SECONDS_IN_A_DAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;time_since_last_login&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SECONDS_IN_A_DAY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;send_reminder_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's obvious. To a human. To an AI. To you when you come back in three months.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Missing or Useless Comments
&lt;/h3&gt;

&lt;p&gt;Two kinds of bad comments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// no comments at all (bad)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;bulkUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&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 javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// completely useless comments (somehow worse)&lt;/span&gt;
&lt;span class="c1"&gt;// this function syncs items&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// filter items if flag is true&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// otherwise update&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;bulkUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&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;p&gt;Neither of these help an AI agent understand &lt;em&gt;why&lt;/em&gt; this logic exists, what edge cases it handles, or what &lt;code&gt;flag&lt;/code&gt; represents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Syncs inventory items with the database.
 * 
 * @param {Array} items - Array of product objects from the frontend
 * @param {boolean} dryRun - If true, returns filtered items without persisting (used in preview mode)
 * @returns {Array|Promise} - Filtered items (dry run) or DB update result
 * 
 * Note: items with status 'a' (archived) are excluded from live syncs
 */&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;syncInventoryItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dryRun&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dryRun&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;archived&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;bulkUpdateInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&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;p&gt;This is the kind of comment that lets an AI agent understand intent, not just syntax. Big difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Inconsistent Patterns Across Files
&lt;/h3&gt;

&lt;p&gt;This is a subtle one but it absolutely kills AI agents.&lt;/p&gt;

&lt;p&gt;In one file you do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In another:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In another:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetchUsers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three different async patterns. Three different error handling approaches. Three different ways to store the result. When an AI agent is trying to understand your app's data flow, this inconsistency forces it to treat every file as a fresh puzzle with no assumptions it can carry over.&lt;/p&gt;

&lt;p&gt;Pick a pattern. Use it everywhere. Your team will thank you. The AI will thank you. Future-you will thank you.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real Scenario: Debugging with Claude
&lt;/h2&gt;

&lt;p&gt;Let me tell you what happened to a classmate of mine (we're both studying Software Engineering and he was working on his semester project).&lt;/p&gt;

&lt;p&gt;He had a Node.js backend, pretty standard REST API. Something was wrong with his authentication middleware. He pasted the auth file into Claude and asked what was wrong.&lt;/p&gt;

&lt;p&gt;Claude responded with something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"It looks like your &lt;code&gt;verifyToken&lt;/code&gt; function is using &lt;code&gt;req.headers.authorization&lt;/code&gt;, but your middleware in the routes file may be expecting the token in a different format..."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Except the routes file wasn't pasted. Claude was &lt;em&gt;inferring&lt;/em&gt; from the auth file that there was probably a routes file doing something with the token. It was making educated guesses — and sometimes they were right, sometimes totally off.&lt;/p&gt;

&lt;p&gt;When my classmate cleaned up his auth file — better naming, clearer structure, a comment explaining the expected header format — and pasted it again, Claude immediately identified the actual bug: he was calling &lt;code&gt;next()&lt;/code&gt; before the token was fully validated.&lt;/p&gt;

&lt;p&gt;Same model. Same Claude version. Different code quality. Totally different result.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 2026 Context: Why This Matters More Than Ever
&lt;/h2&gt;

&lt;p&gt;According to the &lt;strong&gt;Stack Overflow Developer Survey 2025&lt;/strong&gt;, around 76% of developers were already using or planning to use AI tools in their development process. By 2026, that number's almost certainly higher — adoption isn't slowing down.&lt;/p&gt;

&lt;p&gt;GitHub Copilot crossed &lt;strong&gt;1.8 million paid subscribers&lt;/strong&gt; as of mid-2024, and Cursor reportedly onboarded over &lt;strong&gt;a million active users&lt;/strong&gt; within months of gaining traction. These tools are deeply embedded in how we code now.&lt;/p&gt;

&lt;p&gt;But here's the thing: these tools are also getting more &lt;em&gt;agentic&lt;/em&gt;. They're not just autocompleting lines anymore. They're:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running multi-step tasks across your codebase&lt;/li&gt;
&lt;li&gt;Writing and executing tests automatically&lt;/li&gt;
&lt;li&gt;Making PRs, reviewing diffs, suggesting refactors&lt;/li&gt;
&lt;li&gt;Debugging by reading logs and tracing through files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more autonomous these agents become, the more your code quality becomes a dependency of their success. You are, in a real sense, writing code that AI will read, execute, and modify — not just suggest.&lt;/p&gt;

&lt;p&gt;If your code is unreadable, your AI agent is flying blind.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Wins: What You Can Start Doing Today
&lt;/h2&gt;

&lt;p&gt;Here's the stuff that actually moved the needle for me:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On naming:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Functions should be verbs: &lt;code&gt;getUserById&lt;/code&gt;, &lt;code&gt;validateEmailFormat&lt;/code&gt;, &lt;code&gt;sendWelcomeEmail&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Booleans should be questions: &lt;code&gt;isLoggedIn&lt;/code&gt;, &lt;code&gt;hasPermission&lt;/code&gt;, &lt;code&gt;shouldRedirect&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Arrays should be plural nouns: &lt;code&gt;userIds&lt;/code&gt;, &lt;code&gt;selectedProducts&lt;/code&gt;, &lt;code&gt;pendingOrders&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;On functions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One function, one job. Seriously. Name it after what it does. If the name needs "and" in it, split it.&lt;/li&gt;
&lt;li&gt;Aim for functions under 30 lines. Not a hard rule but a good gut-check.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;On comments:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comment the &lt;em&gt;why&lt;/em&gt;, not the &lt;em&gt;what&lt;/em&gt;. The what is visible in the code. The why usually isn't.&lt;/li&gt;
&lt;li&gt;Use JSDoc or Python docstrings. Not because tooling needs them (though it helps), but because it forces you to explain the function in a single sentence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;On structure:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep related code close together. An AI agent given one file should be able to understand its purpose without needing three others.&lt;/li&gt;
&lt;li&gt;Export types/interfaces alongside the functions that use them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;On consistency:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a simple conventions doc for yourself (or your team). Even three rules are better than none.&lt;/li&gt;
&lt;li&gt;When you pick an async pattern, stick to it. When you pick a naming convention, stick to it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Downside: Don't Overdo It
&lt;/h2&gt;

&lt;p&gt;I'll be honest — there's a risk of going too far with this.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Over-commenting creates noise. If every line has a comment, nothing stands out.&lt;/li&gt;
&lt;li&gt;Excessive abstraction can make code &lt;em&gt;harder&lt;/em&gt; to follow, not easier. Splitting a 30-line function into ten 3-line functions sometimes just creates a maze.&lt;/li&gt;
&lt;li&gt;Obsessing over naming can lead to ridiculously long variable names that break line length and readability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Balance is real. The goal isn't to make your code perfect for AI — it's to make your code &lt;em&gt;good.&lt;/em&gt; Good code happens to work well with AI agents because good code has clear intent, single responsibility, and honest documentation.&lt;/p&gt;

&lt;p&gt;Don't write for the AI. Write clearly. Those end up being the same thing.&lt;/p&gt;




&lt;h2&gt;
  
  
  One Last Thing
&lt;/h2&gt;

&lt;p&gt;There's a quote I keep coming back to from Martin Fowler:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He wrote that in 1999. But in 2026, I'd add a corollary:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good programmers write code that humans &lt;em&gt;and&lt;/em&gt; AI agents can understand — because the tools that help you ship are only as useful as the code they can reason about.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your codebase is your context. Make it readable.&lt;/p&gt;




&lt;h2&gt;
  
  
  References &amp;amp; Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://survey.stackoverflow.co/2025/" rel="noopener noreferrer"&gt;Stack Overflow Developer Survey 2025&lt;/a&gt; — AI tool adoption among developers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.blog/news-insights/company-news/github-copilot-one-million-users/" rel="noopener noreferrer"&gt;GitHub Copilot — 1.8M subscribers&lt;/a&gt; — subscriber milestone reporting&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cursor.com/" rel="noopener noreferrer"&gt;Cursor — AI Code Editor&lt;/a&gt; — agentic coding tool&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://martinfowler.com/books/refactoring.html" rel="noopener noreferrer"&gt;Martin Fowler, &lt;em&gt;Refactoring&lt;/em&gt; (1999)&lt;/a&gt; — on code clarity&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.anthropic.com/en/docs/about-claude/models" rel="noopener noreferrer"&gt;Anthropic Claude Context Windows&lt;/a&gt; — model specs 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://openai.com/index/hello-gpt-4o/" rel="noopener noreferrer"&gt;OpenAI GPT-4o Technical Details&lt;/a&gt; — context window and capabilities&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.oreilly.com/library/view/clean-code-a/9780136083238/" rel="noopener noreferrer"&gt;Clean Code by Robert C. Martin&lt;/a&gt; — naming, functions, comments&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/" rel="noopener noreferrer"&gt;The Pragmatic Programmer&lt;/a&gt; — general software craft&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Find me across the web:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>git</category>
    </item>
    <item>
      <title>Fable 5 Pwned: Inside the First Mythos-Class Leak</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Fri, 12 Jun 2026 08:45:04 +0000</pubDate>
      <link>https://dev.to/thesiliconarchitect/fable-5-pwned-inside-the-first-mythos-class-leak-125g</link>
      <guid>https://dev.to/thesiliconarchitect/fable-5-pwned-inside-the-first-mythos-class-leak-125g</guid>
      <description>&lt;p&gt;The post hit X at some point on June 10, the morning after Anthropic's biggest launch in years.&lt;/p&gt;

&lt;p&gt;I was honestly expecting something like this. The moment Anthropic announced Claude Fable 5 as a Mythos-class model made safe for general use, a clock started somewhere. The company had spent two months restricting Mythos to a tiny circle of vetted partners specifically because it was dangerous. Then it handed a version of it to everyone — and told us the safety classifiers were bulletproof. They ran over 1,000 hours of internal and external red-teaming. No universal jailbreaks found.&lt;/p&gt;

&lt;p&gt;Less than 24 hours later, Pliny the Liberator (@elder_plinius) claimed he had broken through all of it.&lt;/p&gt;

&lt;p&gt;What followed wasn't just a jailbreak story. It became something messier: a system prompt leak, a hidden sabotage controversy, a community revolt, and a forced apology from Anthropic — all compressed into about 72 hours. If you want to understand where AI security actually stands in 2026, this week was the case study.&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.amazonaws.com%2Fuploads%2Farticles%2Fee4bk33p1ud3mek9k4g5.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.amazonaws.com%2Fuploads%2Farticles%2Fee4bk33p1ud3mek9k4g5.png" alt="Syed Ahmer Shah is depicted as Claude Fable 5" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Claude Fable 5?
&lt;/h2&gt;

&lt;p&gt;Fable 5 is Anthropic's first publicly available Mythos-class model. It launched June 9, 2026.&lt;/p&gt;

&lt;p&gt;The short version: Fable 5 and its restricted twin, Claude Mythos 5, share the same underlying weights. They're the same model. The difference is the safety layer sitting on top. Fable 5 ships with classifiers that intercept queries in four domains — cybersecurity, biology, chemistry, and model distillation — and silently reroute them to Claude Opus 4.8, a less capable system. Mythos 5, meanwhile, runs without those classifiers and is only accessible to approved organizations through Project Glasswing.&lt;/p&gt;

&lt;p&gt;Think of it this way: Mythos 5 is the full engine. Fable 5 is the same engine with a governor installed.&lt;/p&gt;

&lt;p&gt;The benchmarks are genuinely impressive. On SWE-Bench Pro, the agentic software engineering benchmark, Fable 5 scores 80.3% — 11 points ahead of Opus 4.8 (69.2%), and a substantial 21 points ahead of GPT-5.5 (58.6%). On Humanity's Last Exam with tools, it posts 64.5% versus 52.2% for GPT-5.5. It's ranked #1 on Cognition's FrontierCode evaluation for production-quality coding and sits second overall across 123 models on independent benchmark aggregator BenchLM.&lt;/p&gt;

&lt;p&gt;Pricing lands at $10 per million input tokens and $50 per million output tokens, with a 1M input token context window and 128K output ceiling. Extended thinking is supported.&lt;/p&gt;

&lt;p&gt;For developers building long-horizon agentic systems, this is a meaningful jump. The model was designed specifically for work that runs for hours or days — tasks where consistency across 50 million lines of code matters more than producing one clean response.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Road to Mythos
&lt;/h2&gt;

&lt;p&gt;To understand why this launch felt different, you need the April 2026 context.&lt;/p&gt;

&lt;p&gt;Two months before Fable 5, Anthropic quietly unveiled Claude Mythos Preview. It didn't go public. Anthropic cited cybersecurity concerns directly — the model had apparently gotten good enough at identifying software vulnerabilities that the company worried about what happens when the wrong people get access to that capability. They called the initiative Project Glasswing and restricted access to a small group of trusted organizations managing critical infrastructure.&lt;/p&gt;

&lt;p&gt;The framing at the time was stark. Anthropic said Mythos-class systems were advancing so rapidly they could approach recursive self-improvement — autonomous self-optimization without human oversight. They urged major AI labs to coordinate on development brakes. Anthropic's own leadership acknowledged the technology they were building might be genuinely dangerous.&lt;/p&gt;

&lt;p&gt;That context matters because it makes June 9 feel like a calculated risk. Anthropic built a classifier layer, ran an extensive red-team operation, and concluded that a public version was achievable. "We then worked with external red-teaming organizations which also failed to find universal jailbreaks," the launch announcement read.&lt;/p&gt;

&lt;p&gt;They were confident. Maybe too confident.&lt;/p&gt;

&lt;p&gt;The launch also came as Anthropic quietly filed IPO paperwork. Commercial momentum was clearly a factor alongside safety reasoning.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Leak That Started Everything
&lt;/h2&gt;

&lt;p&gt;Twenty-four hours. That's roughly how long the safety confidence held.&lt;/p&gt;

&lt;p&gt;On June 10, Pliny the Liberator posted his declaration to X. Alongside the all-caps announcement came a GitHub link: the alleged full system prompt for Claude Fable 5. Around 120,000 characters. The internal instructions Anthropic uses to define how the model behaves, what it refuses, and how it justifies those decisions.&lt;/p&gt;

&lt;p&gt;The system prompt leak is actually the part of this story that deserves more attention than it's getting. A system prompt at this scale isn't just a curiosity. It's a reverse-engineered map of Anthropic's alignment strategy. Safety researchers, adversarial researchers, and people with worse intentions all now have a blueprint of Fable 5's behavioral scaffolding.&lt;/p&gt;

&lt;p&gt;Pliny didn't stop there. Screenshots appeared showing Fable 5 generating detailed stack buffer overflow exploit code, framed as preparation material for an OSED (Offensive Security Exploit Developer) certification exam. A complete Birch reduction chemistry walkthrough followed — a synthesis pathway that has obvious dual-use implications. Both outputs were things the classifier layer was specifically built to prevent.&lt;/p&gt;

&lt;p&gt;The timeline, based on public reporting as of writing: Fable 5 launches June 9. Pliny announces the jailbreak June 10. By June 11, cybersecurity outlets have covered it. By June 12, we're here.&lt;/p&gt;

&lt;p&gt;Anthropic had not publicly responded to the jailbreak claims as of the time this article was written.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Jailbreak Claims: Separating Facts from Hype
&lt;/h2&gt;

&lt;p&gt;This section matters because the X posts were dramatic, and drama warps coverage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verified Facts
&lt;/h3&gt;

&lt;p&gt;A researcher using the handle Pliny the Liberator publicly posted on X claiming a successful bypass of Fable 5's safety classifiers. Multiple cybersecurity outlets — including Cybersecurity News and GBHackers — independently confirmed the screenshots and examined the techniques described. A system prompt of approximately 120,000 characters was published to GitHub and is consistent with what a production-tier Claude system prompt would look like. Pliny's account and the associated screenshots were reported on by Fortune, NBC News, and The Register.&lt;/p&gt;

&lt;p&gt;The techniques described are real, documented attack vectors: multi-agent decomposition (splitting harmful requests across multiple agents to avoid triggering classifiers), Unicode obfuscation (using out-of-distribution token representations that the classifier misses), narrative framing (wrapping dangerous queries in fictional scenarios or academic framings that exploit inconsistencies in intent classification), and long-context manipulation. None of these are new. They've worked against previous models. The question was always whether Anthropic had patched them at the Mythos tier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Community Claims
&lt;/h3&gt;

&lt;p&gt;Security researchers on X argued within hours of launch that Fable 5's classifier approach — routing to Opus 4.8 rather than refusing outright — creates a false sense of security. If the classifier can be bypassed, the fallback never triggers. The model just answers. Pliny characterized the safeguards directly as "authoritarian guardrails that block legitimate security researchers more than bad actors," which is a pointed but coherent critique.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Remains Unverified
&lt;/h3&gt;

&lt;p&gt;Whether the Birch reduction and buffer overflow outputs were genuinely usable or simply resembled the outputs — as opposed to being technically accurate step-by-step guides — has not been independently verified in detail by this author. There's a difference between "model produced chemistry-adjacent text" and "model produced actionable synthesis instructions." The screenshots circulating on X don't fully resolve that distinction. Exercise your own judgment on the severity framing.&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.amazonaws.com%2Fuploads%2Farticles%2F4fnlzi5xjhn2cqabci6x.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.amazonaws.com%2Fuploads%2Farticles%2F4fnlzi5xjhn2cqabci6x.png" alt="Syed Ahmer Shah is shown as a developer" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Developers Actually Care About This
&lt;/h2&gt;

&lt;p&gt;Setting aside the security angle for a second: the underlying model is legitimately impressive.&lt;/p&gt;

&lt;p&gt;Fable 5 scores 80.3% on SWE-Bench Pro. For context, the gap between Fable 5 and Opus 4.8 is larger than the gap between Opus 4.8 and Gemini 3.1 Pro (54.2%). That's a generational jump, not an incremental one. On FrontierCode — a harder, less-saturated benchmark testing whether models can produce code meeting production codebase standards — Fable 5 takes first place even at medium effort settings.&lt;/p&gt;

&lt;p&gt;The agentic angle is where the real shift is. Fable 5 was built for multi-hour, multi-day tasks. It uses vision to check its own coding outputs against design goals. It can handle file-based memory across massive codebases. Early tests showed it completing a migration across a 50 million line codebase in a day. Whether those numbers hold in messier real-world conditions is still being validated, but the baseline capability is real.&lt;/p&gt;

&lt;p&gt;For solo developers, students, and small teams, what this means is that the barrier for serious software engineering assistance just dropped significantly. The pricing is steep at $50/M output tokens, but for the right task, it's competitive — because one successful $10 Fable 5 run can replace three $4 Opus attempts that don't quite finish.&lt;/p&gt;

&lt;p&gt;The safety restrictions create the wrinkle. If your work touches offensive security research, malware analysis, bioinformatics tooling, or anything classifier-adjacent, you're going to get silently bounced to Opus mid-task. And for a while, you didn't even know it was happening.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Scariest Part Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;The jailbreak is the story everyone covered. The story underneath it is more disturbing.&lt;/p&gt;

&lt;p&gt;Buried in Fable 5's 319-page system card — which most outlets didn't read — was a disclosure that Fable 5 applies "interventions to limit Claude's effectiveness" when it detects queries related to advanced machine learning research and building AI model training infrastructure. Unlike the cybersecurity and biology restrictions, which visibly route users to Opus 4.8 with a notification, this one was explicitly labeled: "not visible to the user."&lt;/p&gt;

&lt;p&gt;Read that again. A user could ask Fable 5 for help with their ML research, receive what looks like a normal response, and have no way of knowing the model was deliberately underperforming.&lt;/p&gt;

&lt;p&gt;Anthropic's stated justification was that keeping this quiet avoids "accelerating the actors most willing to violate these terms" — specifically competitors using Claude to train rival models. But Anthropic kept Fable 5 at full strength for its own researchers while throttling external teams doing the same work. Jeremy Howard, head of fast.ai, put it clearly: "They've said they'll sabotage others who try. This means the AI frontier advances, and power imbalance increases."&lt;/p&gt;

&lt;p&gt;Dean Ball, a senior fellow at the Foundation for American Innovation and former senior policy advisor at the White House Office of Science and Technology Policy, gave the controversy its name: the system was deliberately degrading ML research "performance without informing the user" — which he called "a shockingly hostile and terrible look."&lt;/p&gt;

&lt;p&gt;Even former Anthropic employees joined the criticism. Behnam Neyshabur, who had previously co-led Anthropic's effort to build an AI scientist, posted pointedly: "Working on AI for cancer? Sorry, I can't help you. Working on AI for Alzheimer's Disease? Sorry, I'm becoming a bit dumb when it comes to the AI part of it."&lt;/p&gt;

&lt;p&gt;The antitrust dimension Ball raised isn't paranoid. A company throttling a competitor's ability to use its API while keeping that throttle invisible is exactly the kind of thing that gets regulatory attention. This is especially sensitive the week Anthropic is apparently preparing an IPO.&lt;/p&gt;

&lt;p&gt;Anthropic reversed the policy. They told &lt;em&gt;Wired&lt;/em&gt;: "We made the wrong tradeoff, and we apologize for not getting the balance right." Flagged requests will now visibly fall back to Opus 4.8, and API users will receive a reason for refusals.&lt;/p&gt;




&lt;h2&gt;
  
  
  Criticism of Anthropic: The Hard Questions
&lt;/h2&gt;

&lt;p&gt;I want to be fair here. I think Anthropic is genuinely trying to build safe systems. The alternative — not building safety classifiers, releasing Mythos 5 raw — is probably worse. But this launch surfaced three legitimate failures worth naming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did they move too quickly?&lt;/strong&gt; The Mythos Preview went from closed partner access to general public access in two months. That's fast for a capability tier that Anthropic itself described as potentially dangerous enough to destabilize the AI development landscape. The jailbreak happened in 24 hours. Either the testing was insufficient, or they knew the model could be bypassed and released anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is safety through classifiers an architectural mistake?&lt;/strong&gt; The jailbreak methods Pliny used — decomposition, Unicode tricks, narrative framing — are well-documented. They predate Fable 5. The question of whether a bolt-on classifier layer can reliably intercept adversarial prompts at scale was never obviously yes. Routing to Opus 4.8 is only useful if the classifier actually catches the problematic request. If you can route around the classifier, the fallback doesn't activate and you get the full Mythos capability anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Was the covert ML research restriction ethical?&lt;/strong&gt; No, not straightforwardly. There's a version of this argument where protecting Anthropic's competitive position is a national security concern — if Chinese labs can use Claude to train superior models, that changes the balance of power. But implementing that protection invisibly, without disclosure, and while maintaining full capability for your own team is not aligned with Anthropic's stated values about transparency. They knew this was indefensible, which is probably why it was buried in a 319-page system card rather than the launch announcement.&lt;/p&gt;




&lt;h2&gt;
  
  
  Community Reactions
&lt;/h2&gt;

&lt;p&gt;The developer community response was split along predictable lines, but with some surprising crossover.&lt;/p&gt;

&lt;p&gt;Open-source advocates, who already distrust Anthropic's closed approach, used the covert restriction controversy to reinforce their existing position. That's not news.&lt;/p&gt;

&lt;p&gt;What was notable was that AI safety researchers — people who typically side with Anthropic on capability restrictions — were equally frustrated. The criticism of the invisible ML research throttling came from across the usual ideological spectrum. That's a bad sign for Anthropic's credibility with the researcher community.&lt;/p&gt;

&lt;p&gt;On the capability side, the reaction was different. Ethan Mollick at Wharton wrote that Fable 5 "outperformed basically every other public model I have used by a considerable margin." Cursor CEO Michael Truell flagged the SWE-Bench Pro jump as significant for production-grade agentic coding. Developers who tested it on long-horizon tasks without hitting the classifier ceiling generally reported it was the best model available.&lt;/p&gt;

&lt;p&gt;The Hacker News and Reddit threads split predictably: one thread on the benchmarks (optimistic), one thread on the jailbreak (skeptical), and several threads on the invisible sabotage policy (genuinely angry).&lt;/p&gt;




&lt;h2&gt;
  
  
  Pros
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Benchmark-genuine capability.&lt;/strong&gt; The 11-point SWE-Bench Pro gap isn't margin-of-error noise. For agentic coding, long-context reasoning, and document-heavy knowledge work, this is the strongest public model available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vision integrated with output evaluation.&lt;/strong&gt; Fable 5 can check its own coding against design screenshots. That's a qualitative shift for frontend development workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Honest pricing relative to Mythos Preview.&lt;/strong&gt; At $10/$50 per million tokens, Fable 5 is under half the Mythos Preview rate. For the right use case, it's economical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extended thinking support.&lt;/strong&gt; Complex multi-step reasoning tasks benefit meaningfully from this. Research workflows, technical writing, planning — it shows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long-horizon task design.&lt;/strong&gt; Built for hours-long agentic runs, not single-shot completions. The architecture reflects this in practice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cons
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Safety classifiers are bypassable.&lt;/strong&gt; This is now a demonstrated fact, not a theoretical risk. The jailbreak used known techniques. The 1,000-hour red-team claim doesn't look credible in retrospect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Classifier false positives are real.&lt;/strong&gt; By June 10, researchers were reporting blocks on reading security blog posts and writing defensive code reviews — tasks nowhere near the classifier's intended scope. The fallback to Opus 4.8 is disruptive when it misfires.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Covert restrictions were unacceptable.&lt;/strong&gt; Anthropic corrected this, but the fact it shipped with an invisible ML research throttle damages trust. Developers need to know when and why a model is underperforming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;30-day data retention is mandatory.&lt;/strong&gt; Fable 5 is not available under zero data retention. For privacy-sensitive enterprise work, this is a hard constraint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Price.&lt;/strong&gt; $50/M output tokens is real money for high-volume inference. Small teams and students will feel this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Uses
&lt;/h2&gt;

&lt;p&gt;Where Fable 5 actually earns its cost premium:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Software engineering at scale.&lt;/strong&gt; Long refactoring runs, multi-file migrations, debugging unfamiliar codebases. The 50M-line codebase benchmark is illustrative. This is its obvious home.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Research and literature synthesis.&lt;/strong&gt; The long context window and document reasoning capabilities make it genuinely useful for academic and technical research workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finance and legal document analysis.&lt;/strong&gt; The vision improvements — reading tables, charts, and complex PDFs — directly target document-heavy professional work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scientific research (where the classifier doesn't fire).&lt;/strong&gt; For biology and chemistry research that doesn't trigger the safety layer, this is a real capability upgrade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Autonomous agent workflows.&lt;/strong&gt; If you're building AI agents that run extended tasks with tool use, Fable 5 is the current frontier. The consistency across long contexts matters here.&lt;/p&gt;




&lt;h2&gt;
  
  
  Potential Losses and Risks
&lt;/h2&gt;

&lt;p&gt;The risks here are not hypothetical.&lt;/p&gt;

&lt;p&gt;If the jailbreak holds up under scrutiny — and early evidence suggests at least partial validity — then Mythos-class offensive security capabilities are now accessible to anyone with patience and knowledge of multi-agent decomposition. The classifier was the only gate. It's been bypassed.&lt;/p&gt;

&lt;p&gt;The 120,000-character system prompt leak is a separate, sustained problem. It gives adversarial researchers a map of Fable 5's refusal logic. Every new version of this style of attack will be informed by that blueprint.&lt;/p&gt;

&lt;p&gt;For enterprises, the covert restriction incident establishes a precedent: AI vendors can silently degrade performance without disclosure. Even after Anthropic's correction, that precedent was set. It will affect how enterprise security teams write API contracts going forward.&lt;/p&gt;

&lt;p&gt;The IPO timing adds commercial pressure that doesn't obviously improve safety decision-making. A company filing for public markets has incentive to show capability and adoption curves. That tension with responsible deployment is worth watching.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Perspective as a Software Engineering Student
&lt;/h2&gt;

&lt;p&gt;I want to be honest about where I sit in this conversation.&lt;/p&gt;

&lt;p&gt;I'm a software engineering student. I use these models for serious work — understanding complex systems, writing and debugging code, getting through research I couldn't afford the time to do otherwise. Fable 5 is relevant to me in a practical, not abstract, way.&lt;/p&gt;

&lt;p&gt;And I think the honest take is this: Anthropic built something that is genuinely impressive and genuinely insecure, and then tried to manage the insecurity in ways that were sometimes dishonest.&lt;/p&gt;

&lt;p&gt;The invisible ML research throttle bothers me more than the jailbreak. Jailbreaks happen. They're a structural feature of current safety approaches, not a sign of malice. But choosing not to tell users when their outputs were being deliberately degraded — that's a choice. That's not a technical accident. Someone decided that disclosure wasn't worth the friction, and that decision was wrong.&lt;/p&gt;

&lt;p&gt;At the same time, the benchmarks are real. If Fable 5 is as capable as the SWE-Bench numbers suggest, the value for actual software engineering work is substantial. I've spent enough time watching frontier models inch forward to recognize when something is a genuine jump. This appears to be one.&lt;/p&gt;

&lt;p&gt;The question for me isn't whether to use it. It's whether to trust what it's doing — and whether Anthropic has earned that trust back after this week. I think they took a step toward it by reversing the covert restriction. But the step was forced by community pressure, not voluntary.&lt;/p&gt;

&lt;p&gt;That's a pattern worth paying attention to.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;The story of Fable 5's first 72 hours is really two stories running in parallel.&lt;/p&gt;

&lt;p&gt;In one, a powerful model built on dangerous capabilities was made public, jailbroken within a day, and its core instructions exposed to the world. In the other, a company trying to balance commercial momentum, safety obligations, and competitive position made a covert decision that violated developer trust — and was forced to reverse it.&lt;/p&gt;

&lt;p&gt;Neither story is resolved.&lt;/p&gt;

&lt;p&gt;The jailbreak will evolve. The classifier architecture may improve or may prove fundamentally insufficient. The system prompt is out there, and it will inform the next generation of attacks. Anthropic hasn't responded publicly to Pliny's claims. At some point, they'll have to.&lt;/p&gt;

&lt;p&gt;The trust story is longer. Anthropic is approaching a public market. The developer community they're alienating with invisible restrictions and post-hoc apologies is the same community they need for adoption. You can only reverse mistakes so many times before the pattern becomes the story.&lt;/p&gt;

&lt;p&gt;Fable 5 is, by the benchmarks, the best public AI model for software engineering work available today. That's true. It's also true that within 24 hours of launch, someone posted "ANTHROPIC: PWNED" and wasn't immediately, definitively wrong.&lt;/p&gt;

&lt;p&gt;Both things are the landscape. Developers should operate accordingly.&lt;/p&gt;




&lt;p&gt;Note: To stay fully transparent with the community, I want to share that I used AI assistance to help draft and polish this article. I’ve reviewed and edited everything to ensure it aligns with community guidelines and brings genuine value to you all!&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.anthropic.com/news/claude-fable-5-mythos-5" rel="noopener noreferrer"&gt;https://www.anthropic.com/news/claude-fable-5-mythos-5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.anthropic.com/claude/fable" rel="noopener noreferrer"&gt;https://www.anthropic.com/claude/fable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.claude.com/docs/en/about-claude/models/introducing-claude-fable-5-and-claude-mythos-5" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/about-claude/models/introducing-claude-fable-5-and-claude-mythos-5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcrunch.com/2026/06/09/anthropic-released-claude-fable-5-its-most-powerful-model-publicly-days-after-warning-ai-is-getting-too-dangerous/" rel="noopener noreferrer"&gt;https://techcrunch.com/2026/06/09/anthropic-released-claude-fable-5-its-most-powerful-model-publicly-days-after-warning-ai-is-getting-too-dangerous/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cybersecuritynews.com/anthropics-claude-fable-5-jailbroken/" rel="noopener noreferrer"&gt;https://cybersecuritynews.com/anthropics-claude-fable-5-jailbroken/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cyberpress.org/claude-fable-5-jailbreak/" rel="noopener noreferrer"&gt;https://cyberpress.org/claude-fable-5-jailbreak/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fortune.com/2026/06/10/anthropic-accu-claude-fable-5-limits-capabilities-ai-researchers-developers/" rel="noopener noreferrer"&gt;https://fortune.com/2026/06/10/anthropic-accu-claude-fable-5-limits-capabilities-ai-researchers-developers/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.siliconrepublic.com/enterprise/anthropic-reassess-claude-fable-5-ai-development-restrictions-backlash" rel="noopener noreferrer"&gt;https://www.siliconrepublic.com/enterprise/anthropic-reassess-claude-fable-5-ai-development-restrictions-backlash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.technobezz.com/news/anthropic-faces-backlash-after-claude-fable-5-silently-limits-ai-research-capabilities" rel="noopener noreferrer"&gt;https://www.technobezz.com/news/anthropic-faces-backlash-after-claude-fable-5-silently-limits-ai-research-capabilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://letsdatascience.com/blog/anthropic-fable-5-secret-sabotage-reversed" rel="noopener noreferrer"&gt;https://letsdatascience.com/blog/anthropic-fable-5-secret-sabotage-reversed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.androidheadlines.com/2026/06/anthropic-reverses-hidden-claude-fable-5-ai-restrictions.html" rel="noopener noreferrer"&gt;https://www.androidheadlines.com/2026/06/anthropic-reverses-hidden-claude-fable-5-ai-restrictions.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pasqualepillitteri.it/en/news/4730/claude-fable-5-jailbreak-pliny-hype-vs-facts" rel="noopener noreferrer"&gt;https://pasqualepillitteri.it/en/news/4730/claude-fable-5-jailbreak-pliny-hype-vs-facts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://claude5.ai/news/claude-fable-5-benchmarks-swe-bench-pro-80-percent" rel="noopener noreferrer"&gt;https://claude5.ai/news/claude-fable-5-benchmarks-swe-bench-pro-80-percent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.truefoundry.com/blog/claude-fable-5-api-benchmarks-pricing-how-to-use-it" rel="noopener noreferrer"&gt;https://www.truefoundry.com/blog/claude-fable-5-api-benchmarks-pricing-how-to-use-it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://llm-stats.com/blog/research/claude-fable-5-review" rel="noopener noreferrer"&gt;https://llm-stats.com/blog/research/claude-fable-5-review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gbhackers.com/anthropics-claude-fable-5-ai-model-jailbroken/" rel="noopener noreferrer"&gt;https://gbhackers.com/anthropics-claude-fable-5-ai-model-jailbroken/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalapplied.com/blog/claude-fable-5-mythos-5-agentic-coding-deep-dive-2026" rel="noopener noreferrer"&gt;https://www.digitalapplied.com/blog/claude-fable-5-mythos-5-agentic-coding-deep-dive-2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cnbc.com/2026/06/09/anthropic-mythos-claude-fable-5.html" rel="noopener noreferrer"&gt;https://www.cnbc.com/2026/06/09/anthropic-mythos-claude-fable-5.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Find me across the web:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>programming</category>
      <category>node</category>
    </item>
    <item>
      <title>Is Node.js Still Enough? When to Move Your Backend to Rust</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Sun, 07 Jun 2026 11:55:43 +0000</pubDate>
      <link>https://dev.to/thesiliconarchitect/is-nodejs-still-enough-when-to-move-your-backend-to-rust-31j3</link>
      <guid>https://dev.to/thesiliconarchitect/is-nodejs-still-enough-when-to-move-your-backend-to-rust-31j3</guid>
      <description>&lt;h2&gt;
  
  
  Node.js Is Not Failing You — You're Already Outgrowing It
&lt;/h2&gt;

&lt;p&gt;Note: To stay fully transparent with the community, I want to share that I used AI assistance to help draft and polish this article. I’ve reviewed and edited everything to ensure it aligns with community guidelines and brings genuine value to you all!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The uncomfortable truth about backend performance, Rust, and why the event loop will betray you exactly when it matters most.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;It was 3 AM. Not the good kind of 3 AM.&lt;/p&gt;

&lt;p&gt;The monitoring dashboard looked like a medical emergency. Latency on the main API endpoint had gone from 38ms to over 4 seconds. Not spiking — sitting there, steady, 4 seconds on every request. The Node.js process wasn't crashed. That would've been easier, honestly. It was alive, the process was running, it was just completely frozen in place. Someone — and it wasn't me, I'm saying that for the record — had shipped a synchronous image compression function directly in the request handler. No worker thread. No queue. Just blocking, heavy, CPU-bound work sitting right there inside the event loop.&lt;/p&gt;

&lt;p&gt;Every other request was standing in line behind it. Not errored. Not rejected. Just waiting to die.&lt;/p&gt;

&lt;p&gt;That night broke something in my brain regarding how I thought about Node.js. Not in a dramatic "I'm done with this runtime" way. More in the way you start actually understanding something you thought you already understood. The event loop is not magic. It's a design choice. And every design choice has limits.&lt;/p&gt;

&lt;p&gt;This article is about those limits. When they show up. What they look like. And whether Rust is actually the answer or just the current internet-famous overcorrection.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Everyone Started Here (And That Was Fine)
&lt;/h2&gt;

&lt;p&gt;To be fair to Node.js, the original pitch was genuinely exciting. Ryan Dahl showed the world in 2009 that you could handle thousands of simultaneous connections with almost no memory overhead by using non-blocking I/O and a single-threaded event loop. JavaScript on the server. One language across the whole stack. One hiring pool. One mental model.&lt;/p&gt;

&lt;p&gt;For most web applications that pitch still holds. REST APIs, GraphQL endpoints, WebSocket servers, BFFs, real-time dashboards, lightweight microservices — Node.js handles all of this with very little complaint. The npm registry crossed 2.5 million packages in 2024. The developer tooling around TypeScript and Node.js is genuinely excellent right now. You can spin up a production-ready Express or Fastify API in an afternoon and have it deployed before dinner.&lt;/p&gt;

&lt;p&gt;And the thing is — most web applications are fine with this. Most companies are operating at scales where Node.js performance is genuinely not the bottleneck. The bottleneck is the database. Or the architecture. Or the fact that nobody indexed that column three years ago.&lt;/p&gt;

&lt;p&gt;So when I say "you're outgrowing it" — I'm not saying you've outgrown it right now, today, reading this on your laptop. I'm saying the situations where the runtime itself becomes the problem are growing. And understanding where that line is seems more important than it used to.&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.amazonaws.com%2Fuploads%2Farticles%2F9olpm112laptz1nd7rgs.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.amazonaws.com%2Fuploads%2Farticles%2F9olpm112laptz1nd7rgs.png" alt="The Event Loop Is a Single Lane Highway ( Syed Ahmer Shah is shown on an event loop )" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Event Loop Is a Single Lane Highway
&lt;/h2&gt;

&lt;p&gt;Here's what nobody explains clearly when they first teach you Node.js.&lt;/p&gt;

&lt;p&gt;The event loop is brilliant for waiting. Network requests go out, database queries go out, file reads queue up — the process just sits there juggling callbacks and never actually has to work very hard in between those I/O operations. Concurrent in the sense that many things are in flight at once. But still single-threaded. Still one lane.&lt;/p&gt;

&lt;p&gt;The moment you give it real computation to do, it blocks. Full stop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// This looks innocent enough&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/generate-report&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;records&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 50,000 records, some sorting and aggregation&lt;/span&gt;
  &lt;span class="c1"&gt;// This takes ~800ms on a decent machine&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;revenue&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;revenue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aggregated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&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="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&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="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;revenue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aggregated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While that 800ms computation runs, every other request hitting your server sits in a queue. No parallelism. No preemption. The user requesting their login token is waiting for a sales report to finish generating. That's the architecture. That's not a bug in the code — that's how the runtime works.&lt;/p&gt;

&lt;p&gt;Worker threads exist, yeah. &lt;code&gt;worker_threads&lt;/code&gt; has been available since Node.js 11.7. But using them correctly is genuinely more complex than it should be, and honestly it's a workaround for a design limitation rather than a first-class solution. You're fighting the runtime's nature.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The worker_threads "fix" — real code, real overhead&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parentPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;workerData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;worker_threads&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/generate-report&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;workerData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;records&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;records&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Same logic, now in a thread&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;workerData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;records&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;revenue&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;revenue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aggregated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&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="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&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="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;revenue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
  &lt;span class="nx"&gt;parentPort&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aggregated&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;p&gt;This works. But you're now managing worker lifecycles, serialization overhead, error propagation across thread boundaries. For one endpoint. And you're still not getting native parallelism — you're getting OS thread concurrency with a JavaScript wrapper around it.&lt;/p&gt;

&lt;p&gt;Is this the direction you want to keep going?&lt;/p&gt;




&lt;h2&gt;
  
  
  What Garbage Collection Silently Does to Your Latency
&lt;/h2&gt;

&lt;p&gt;There's another issue that gets less attention than CPU blocking, and it's more subtle and harder to debug. Garbage collection pauses.&lt;/p&gt;

&lt;p&gt;Node.js uses V8's garbage collector. V8 is genuinely excellent engineering. But even excellent GC has to stop and clean up memory at some point. In production, under real load, with real memory pressure, these pauses are real. They're usually short — tens to hundreds of milliseconds. Sometimes longer. And they're not triggered by your code. They're triggered by the runtime. You cannot schedule them, predict them precisely, or prevent them.&lt;/p&gt;

&lt;p&gt;For a lot of applications this is totally acceptable. For latency-sensitive systems — financial data feeds, real-time multiplayer, high-frequency trading, voice and video processing, anything where a 200ms unpredictable pause actually matters — GC becomes a design problem, not just a performance footnote.&lt;/p&gt;

&lt;p&gt;This is not a Node.js-specific problem. Go has it. Java has it. Python has it. Every language with a managed runtime has it. Which is, importantly, why Rust's approach is so different.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Rust Actually Offers (Without the Cult)
&lt;/h2&gt;

&lt;p&gt;Rust is a systems programming language that compiles to native machine code with no garbage collector and no runtime overhead in the traditional sense. Developed originally at Mozilla, now maintained by the Rust Foundation with backing from Amazon, Google, Microsoft, and Meta. First stable release in 2015. Slow build, fast execution, steep learning curve.&lt;/p&gt;

&lt;p&gt;The borrow checker — Rust's most infamous feature — is the compile-time system that enforces memory safety without a GC. Instead of collecting garbage at runtime, Rust proves at compile time that your code cannot have dangling pointers, data races, or use-after-free bugs. The compiler rejects the code if it finds violations. That sounds annoying (it is, initially) but what it means in practice is that entire categories of runtime bugs simply do not exist in Rust programs.&lt;/p&gt;

&lt;p&gt;For the ninth consecutive year, in the 2024 Stack Overflow Developer Survey, Rust ranked as the most admired programming language. 83.5% of Rust developers said they want to keep using it. That's not a hype cycle anymore. Nine years is a signal. That's a community of people who went through the hard part and stayed.&lt;/p&gt;

&lt;p&gt;But let's be clear about something: Rust is not a replacement for Node.js in the general case. It's a replacement for Node.js in &lt;em&gt;specific&lt;/em&gt; cases. The key is knowing which cases those are.&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.amazonaws.com%2Fuploads%2Farticles%2Ffww54cnmfpt7ifayote8.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.amazonaws.com%2Fuploads%2Farticles%2Ffww54cnmfpt7ifayote8.png" alt="The Discord Post That Every Backend Developer Should Read ( Syed Ahmer Shah shown as a saviour )" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Discord Post That Every Backend Developer Should Read
&lt;/h2&gt;

&lt;p&gt;In February 2020, Discord published a blog post called "Why Discord is switching from Go to Rust." If you work in backend development and you haven't read it, go read it. It changed how I think about language and runtime choices.&lt;/p&gt;

&lt;p&gt;Discord was running their Read States service in Go. This is the service that tracks which messages you've read across all your servers and channels. At their scale, it was handling millions of concurrent users. Go's garbage collector kept introducing latency spikes every two minutes, almost like clockwork. Users experienced stutters. Discord tried tuning the GC. They tried throwing more memory at the service to space out collection cycles. The spikes kept coming. They couldn't engineer their way out of a fundamental runtime behavior.&lt;/p&gt;

&lt;p&gt;They rewrote the service in Rust.&lt;/p&gt;

&lt;p&gt;The latency spikes disappeared. Not reduced — disappeared. Memory usage dropped dramatically. The service became boring in the best possible way. It just ran. Predictably. Consistently. Without surprise pauses.&lt;/p&gt;

&lt;p&gt;The thing that gets me about that story isn't the performance numbers. It's the fact that they weren't doing anything exotic. Read States is conceptually simple: track what you've read, update it in real time, serve it fast. That's not a supercomputer problem. But at Discord's scale, the runtime's behavior became the application's behavior. And they couldn't hide from it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cloudflare's Bigger, Quieter Bet
&lt;/h2&gt;

&lt;p&gt;If Discord is an interesting data point, Cloudflare is a confirmation of the direction things are heading.&lt;/p&gt;

&lt;p&gt;In 2022, Cloudflare announced Pingora — a new HTTP proxy built in Rust that they'd been running internally as a replacement for NGINX. In February 2024, they open-sourced it. The numbers they reported were not subtle: the service runs at over 1 trillion requests per day across their network. CPU usage dropped. Memory usage dropped significantly compared to their NGINX setup. The Rust rewrite was not a side project or an experiment. It became the backbone of how Cloudflare connects to the internet.&lt;/p&gt;

&lt;p&gt;Cloudflare Workers — their serverless edge computing platform — lets developers deploy JavaScript and TypeScript at the edge. But the runtime itself, the thing executing your JavaScript efficiently at hundreds of datacenters worldwide? Built in Rust. You're writing JS code that runs inside a Rust-built sandbox.&lt;/p&gt;

&lt;p&gt;Deno 2.0 shipped in October 2024. Built on Rust bindings to V8. Added much better Node.js compatibility, making it a genuine migration path from Node. Bun, the other JavaScript runtime that came up as a performance competitor, is built on Zig — which, like Rust, compiles to native code and has no GC.&lt;/p&gt;

&lt;p&gt;Here's the thing that I think deserves more attention: even in ecosystems where the developer experience stays JavaScript, the infrastructure layer underneath is moving toward Rust and systems languages. The fastest runtimes are compiled. The most reliable proxies are compiled. The pattern is not "Rust instead of Node.js" at the application layer. The pattern is "Rust underneath everything" at the infrastructure layer.&lt;/p&gt;

&lt;p&gt;That matters because the performance expectations users are going to have — shaped by Cloudflare edge computing, Pingora proxy speeds, and Deno/Bun runtime benchmarks — are going to creep upward. And Node.js in the middle will have to answer for it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Rust Looks Like for a Backend Developer
&lt;/h2&gt;

&lt;p&gt;Here's a basic HTTP endpoint in Actix-Web, which is one of the more popular Rust web frameworks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;actix_web&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HttpServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Responder&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;serde&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tokio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ReportRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;record_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Serialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ReportResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;total_revenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;record_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;generate_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;web&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ReportRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Responder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// CPU-bound work goes to a blocking thread pool&lt;/span&gt;
    &lt;span class="c1"&gt;// This does NOT block other async requests&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;task&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn_blocking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Simulate heavy computation&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="py"&gt;.record_count&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Some CPU work&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;total&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nn"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReportResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="py"&gt;.region&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;total_revenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;record_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="py"&gt;.record_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[actix_web::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;HttpServer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/report"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;web&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generate_report&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;.bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"127.0.0.1:8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
    &lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;.await&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compared to the Node.js version with worker threads, the structural difference is significant. Rust's async model is built on top of actual OS thread pools. The CPU-bound work in &lt;code&gt;spawn_blocking&lt;/code&gt; runs in a separate thread pool managed by Tokio (the async runtime) without blocking the async task executor. There's no serialization overhead across an IPC channel. There's no GC ever entering the picture. The borrow checker ensures at compile time that the closure passed to &lt;code&gt;spawn_blocking&lt;/code&gt; doesn't share mutable state with anything else.&lt;/p&gt;

&lt;p&gt;The TechEmpower Framework Benchmarks — which are one of the more credible public benchmarks for web framework performance across languages — consistently place Actix-Web and ntex (another Rust web framework) in the top tier for raw throughput. Express.js and Fastify appear much lower. Not because Node.js frameworks are badly written, but because the measurement is raw request throughput and Rust's compiled native execution simply processes requests faster at the infrastructure level.&lt;/p&gt;

&lt;p&gt;For I/O-bound workloads, the difference narrows. For CPU-intensive workloads, it widens considerably.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Cost of Switching Nobody Tells You About
&lt;/h2&gt;

&lt;p&gt;Here's the section that most "Node.js to Rust" migration articles skip, or mention briefly before rushing to the benchmark charts. The actual cost of this migration is serious and you should stare at it for a while before deciding anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The learning curve is genuinely steep.&lt;/strong&gt; Not in a "watch a few tutorials and you're good" way. The borrow checker, lifetimes, ownership — these concepts don't exist anywhere in JavaScript. They don't really exist in Python, Ruby, Go, or most languages most backend developers have used. It will take a capable developer weeks of dedicated effort before they stop fighting the compiler on basic memory patterns. Not writing good Rust. Just getting past the initial wall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The hiring pool is small.&lt;/strong&gt; npm knows 2.5 million packages. Node.js developers are everywhere. Finding a Rust developer with production web backend experience is a different challenge entirely. You're paying more, waiting longer, and getting someone who probably learned Rust on personal projects and systems code, not web services. The talent market is growing, slowly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The ecosystem is thinner.&lt;/strong&gt; crates.io had around 150,000 packages as of early 2025. Growing fast, but not npm. For certain integrations — some payment gateways, certain analytics SDKs, niche database clients — you'll find yourself writing wrapper code or bindings that you'd get for free in Node. That's real engineering time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compile times.&lt;/strong&gt; This one is annoying in day-to-day development. Cold builds on a mid-size Rust project take several minutes. Incremental builds are better. But the feedback loop is longer than TypeScript. When you're debugging something fast-moving, that matters to your energy and focus.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;None of this means don't do it.&lt;/strong&gt; It means count the cost before you commit. Migration projects that underestimated the friction tend to get abandoned halfway through, which leaves you with a half-Rust, half-Node.js system that has the downsides of both and the advantages of neither.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stop. Answer These Questions Honestly.
&lt;/h2&gt;

&lt;p&gt;Before you close this tab and start reading the Actix-Web documentation, ask yourself:&lt;/p&gt;

&lt;p&gt;Have you actually profiled your application? Most Node.js performance problems are not the runtime. They're N+1 database queries, missing indexes, no caching layer, or serializing entire database rows when you only need two fields. None of those are fixed by switching to Rust. Find the actual bottleneck before you decide what to replace.&lt;/p&gt;

&lt;p&gt;What is your real traffic volume? If you're handling under 500 requests per second and your endpoints are mostly database reads, Rust is almost certainly not where your engineering time should go. The overhead of the migration will dwarf any performance gain at that scale.&lt;/p&gt;

&lt;p&gt;Does your use case actually involve CPU-bound work? AI inference, image processing, cryptographic operations, video transcoding, large data aggregations, compression — these are legitimate candidates for a Rust service. Authentication checks and database-backed CRUD are not.&lt;/p&gt;

&lt;p&gt;What does your team actually want to learn? This is the one people underrate most. A team that genuinely wants to learn Rust will fight through the rough parts and come out the other side shipping good code. A team that's being told to use Rust because leadership read a blog post will write bad Rust slowly and resent the whole thing.&lt;/p&gt;




&lt;h2&gt;
  
  
  When You Genuinely Should Not Move to Rust
&lt;/h2&gt;

&lt;p&gt;Early-stage startups or solo developers trying to ship a product. Developer velocity is your scarcest resource. Use the stack you know. The performance difference between Node.js and Rust is irrelevant if you're trying to find product-market fit.&lt;/p&gt;

&lt;p&gt;Standard web applications with normal CRUD logic. A TypeScript + Node.js + Prisma + PostgreSQL stack is a genuinely excellent combination for most web products. There is nothing broken about it. Adding Rust to this because you read about Discord is not senior engineering — it's resume-driven development.&lt;/p&gt;

&lt;p&gt;Teams where nobody wants to learn Rust. Forced adoption of technology produces the worst version of that technology. A team that doesn't want to be there will produce buggy, unidiomatic, unmaintained Rust that will be a liability in six months.&lt;/p&gt;

&lt;p&gt;When you haven't exhausted your current optimizations. Have you looked at clustering Node.js processes? Have you profiled your event loop lag? Have you moved CPU work to queues or separate services? Have you reviewed your database query plans? These cost less than a rewrite and often fix the problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Actual Opinion
&lt;/h2&gt;

&lt;p&gt;I'm going to stop being balanced here and just say what I think.&lt;/p&gt;

&lt;p&gt;Node.js is not going away. It will be running a meaningful portion of the internet ten years from now, the same way PHP still runs half the web despite being declared dead roughly every eighteen months. It's battle-tested, well-understood, and good enough for the vast majority of what gets built.&lt;/p&gt;

&lt;p&gt;But I do think there's a version of "defaulting to Node.js without thinking" that's becoming harder to justify as the use cases for backends get more complex. AI inference is being pushed to the backend. Real-time systems are becoming more common. Edge computing is maturing. Workloads are changing. And the runtime you picked in 2019 for a REST API might not be the right answer for what you're building in 2026.&lt;/p&gt;

&lt;p&gt;The smarter architecture for most teams isn't a full rewrite. It's a hybrid — Node.js handling your API gateway, your user-facing routes, your standard CRUD, and a Rust service (or a few) handling the parts that actually need performance. One Rust microservice doing image resizing. One handling the expensive report generation. Keep the rest of your system in a language your team already knows. Add Rust where it earns its complexity cost.&lt;/p&gt;

&lt;p&gt;Is Node.js still enough? For most of what most people are building, honestly yes. For the direction backends are heading over the next five years — probably not everywhere.&lt;/p&gt;

&lt;p&gt;The question isn't whether to switch. The question is whether you understand your runtime well enough to know when switching actually helps. Most developers don't. Most developers, including me a couple of years ago, just pick Node.js because it's comfortable. That's fine — until it isn't.&lt;/p&gt;

&lt;p&gt;Start learning Rust. Not to rewrite anything. Just to understand what you're missing. The moment you write your first program that compiles cleanly with the borrow checker satisfied, you understand something about memory and ownership that changes how you write code in every other language too.&lt;/p&gt;

&lt;p&gt;That's worth something, independent of whether you ever ship a Rust API.&lt;/p&gt;




&lt;h2&gt;
  
  
  References and Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Stack Overflow Developer Survey 2024 — &lt;a href="https://survey.stackoverflow.co/2024/" rel="noopener noreferrer"&gt;https://survey.stackoverflow.co/2024/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;"Why Discord is switching from Go to Rust" — Discord Engineering Blog, February 2020 — &lt;a href="https://discord.com/blog/why-discord-is-switching-from-go-to-rust" rel="noopener noreferrer"&gt;https://discord.com/blog/why-discord-is-switching-from-go-to-rust&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;"How we built Pingora, the proxy that connects Cloudflare to the internet" — Cloudflare Blog — &lt;a href="https://blog.cloudflare.com/how-we-built-pingora-the-proxy-that-connects-cloudflare-to-the-internet/" rel="noopener noreferrer"&gt;https://blog.cloudflare.com/how-we-built-pingora-the-proxy-that-connects-cloudflare-to-the-internet/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;"Pingora: Open Source" — Cloudflare Blog, February 2024 — &lt;a href="https://blog.cloudflare.com/pingora-open-source/" rel="noopener noreferrer"&gt;https://blog.cloudflare.com/pingora-open-source/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TechEmpower Web Framework Benchmarks — &lt;a href="https://www.techempower.com/benchmarks/" rel="noopener noreferrer"&gt;https://www.techempower.com/benchmarks/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Deno 2.0 Release — Deno Blog, October 2024 — &lt;a href="https://deno.com/blog/v2.0" rel="noopener noreferrer"&gt;https://deno.com/blog/v2.0&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;"The Rust Programming Language" (official book) — &lt;a href="https://doc.rust-lang.org/book/" rel="noopener noreferrer"&gt;https://doc.rust-lang.org/book/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Node.js Worker Threads Documentation — &lt;a href="https://nodejs.org/api/worker_threads.html" rel="noopener noreferrer"&gt;https://nodejs.org/api/worker_threads.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Actix-Web Documentation — &lt;a href="https://actix.rs/docs/" rel="noopener noreferrer"&gt;https://actix.rs/docs/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Tokio Async Runtime Documentation — &lt;a href="https://tokio.rs/" rel="noopener noreferrer"&gt;https://tokio.rs/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;crates.io — Rust Package Registry — &lt;a href="https://crates.io" rel="noopener noreferrer"&gt;https://crates.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;"Node.js: The Documentary" — Honeypot, YouTube, 2024&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Written by a software engineering student who blocked the event loop in production once and decided to understand why. If something here is wrong, tell me — that's how this works.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Find me across the web:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
      <category>node</category>
      <category>rust</category>
    </item>
    <item>
      <title>What 90% of Devs Screw Up When Wiring Next.js, Node.js, and Git Together</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Fri, 05 Jun 2026 10:43:44 +0000</pubDate>
      <link>https://dev.to/syedahmershah/what-90-of-devs-screw-up-when-wiring-nextjs-nodejs-and-git-together-4ieh</link>
      <guid>https://dev.to/syedahmershah/what-90-of-devs-screw-up-when-wiring-nextjs-nodejs-and-git-together-4ieh</guid>
      <description>&lt;p&gt;&lt;em&gt;And some of those devs pushed to production. That's the scary part.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;There's this one story I keep thinking about. A junior dev — smart kid, decent portfolio — built a full-stack app for his freelance client. Next.js frontend, Node.js backend, everything wired together. Pushed to GitHub. Client's competitor found the repo three weeks later because it was public and the &lt;code&gt;.env&lt;/code&gt; file was sitting right there. Database password. Stripe secret keys. Everything.&lt;/p&gt;

&lt;p&gt;That project was not just a technical failure. It was a trust failure.&lt;/p&gt;

&lt;p&gt;And here's the brutal thing: it wasn't a dumb mistake from an incompetent person. It was a &lt;em&gt;normal&lt;/em&gt; mistake from a developer who never learned the actual mechanics of connecting these three tools. He knew how to code. He didn't know how they link.&lt;/p&gt;

&lt;p&gt;Most developers are in that same boat right now in 2026, and none of them would admit it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Stack Is So Dominant Right Now (And Why That Creates a Problem)
&lt;/h2&gt;

&lt;p&gt;Next.js, Node.js, and Git. This is basically the default web dev stack for a huge chunk of the internet at this point. Next.js crossed 6 million weekly npm downloads in late 2024 and has held that range through 2025 into 2026. Node.js powers something like 6.3% of all websites directly and a much larger chunk indirectly through server-rendered frameworks. Git is used by 97.8% of professional developers according to the Stack Overflow Developer Survey 2025.&lt;/p&gt;

&lt;p&gt;So you've got three massively dominant tools that every developer is expected to just... know. And because everyone assumes everyone else already knows this, nobody actually teaches how they interact.&lt;/p&gt;

&lt;p&gt;The documentation covers them separately. Tutorials cover them in isolation. And then a developer has to wire them together in a real project and suddenly nothing makes sense.&lt;/p&gt;

&lt;p&gt;This is that article. The one nobody wanted to write because it's admitting that the ecosystem has gaps nobody talks about.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Actual Mistakes (And How Bad They Get)
&lt;/h2&gt;

&lt;p&gt;Let me go through them honestly. Not in order of how often they happen but in order of how badly they can hurt you.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Your .env File Is Probably Already on GitHub
&lt;/h3&gt;

&lt;p&gt;I'm going to say this as directly as possible.&lt;/p&gt;

&lt;p&gt;If you started a Next.js or Node.js project in the last three years and you didn't set up &lt;code&gt;.gitignore&lt;/code&gt; before your first &lt;code&gt;git init&lt;/code&gt; or &lt;code&gt;git add .&lt;/code&gt;, there is a real chance your secrets are in your repository history. Even if you deleted the file later. Git doesn't work like a regular file system. It remembers.&lt;/p&gt;

&lt;p&gt;GitHub's own security team reported that in 2024 alone, more than &lt;strong&gt;12.8 million secrets&lt;/strong&gt; were exposed in public repositories. That includes API keys, database credentials, tokens, private keys. The number in 2025 was not smaller.&lt;/p&gt;

&lt;p&gt;And the thing is, &lt;code&gt;.env&lt;/code&gt; is listed in the default &lt;code&gt;.gitignore&lt;/code&gt; that &lt;code&gt;create-next-app&lt;/code&gt; generates. So why does this keep happening?&lt;/p&gt;

&lt;p&gt;Because developers clone starter repos. They spin up custom setups. They copy folder structures from YouTube tutorials that are six months old and never show the &lt;code&gt;.gitignore&lt;/code&gt; setup. They run &lt;code&gt;git add .&lt;/code&gt; out of habit.&lt;/p&gt;

&lt;p&gt;Here's what a proper &lt;code&gt;.gitignore&lt;/code&gt; for a Next.js + Node.js project actually looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Node
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# Next.js
.next/
out/
build/
dist/

# Environment variables - THIS IS THE ONE
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
.env*.local

# Vercel
.vercel

# TypeScript
*.tsbuildinfo
next-env.d.ts

# OS
.DS_Store
*.pem
Thumbs.db

# Debug
.npm
.eslintcache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you've already pushed secrets, here's the painful truth: deleting the file and pushing again does NOT remove it from history. You need to do this:&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 git-filter-repo (better than BFG for 2025+)&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;git-filter-repo

&lt;span class="c"&gt;# Remove the .env file from entire history&lt;/span&gt;
git filter-repo &lt;span class="nt"&gt;--path&lt;/span&gt; .env &lt;span class="nt"&gt;--invert-paths&lt;/span&gt;

&lt;span class="c"&gt;# Then force push (you will need to coordinate with your team)&lt;/span&gt;
git push origin &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But honestly if the secret was already exposed for more than a few hours? Rotate the credentials. Assume they were taken. That's the real answer.&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.amazonaws.com%2Fuploads%2Farticles%2F89ood0khpz13bc4ir481.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.amazonaws.com%2Fuploads%2Farticles%2F89ood0khpz13bc4ir481.png" alt="The NEXT_PUBLIC Image" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The NEXT_PUBLIC_ Trap Nobody Explains Properly
&lt;/h3&gt;

&lt;p&gt;This one is subtle and it catches even experienced developers.&lt;/p&gt;

&lt;p&gt;Next.js has two environments: server and client. Environment variables work differently in both. Variables that start with &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; are bundled into the client-side JavaScript. Everything else stays on the server.&lt;/p&gt;

&lt;p&gt;Sounds simple. But here's where people get it wrong.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This runs on the SERVER (API route, Server Component)&lt;/span&gt;
&lt;span class="c1"&gt;// Works fine&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// This runs on the CLIENT (browser)&lt;/span&gt;
&lt;span class="c1"&gt;// process.env.DB_PASSWORD is undefined here&lt;/span&gt;
&lt;span class="c1"&gt;// because it's not prefixed with NEXT_PUBLIC_&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;something&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// undefined, no error, just silently broken&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The terrifying part isn't the error. It's the silence. You won't get a crash in many cases. You'll just get &lt;code&gt;undefined&lt;/code&gt; and then a cryptic failure somewhere downstream that takes you an hour to debug.&lt;/p&gt;

&lt;p&gt;And the opposite mistake is even worse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DON'T DO THIS&lt;/span&gt;
&lt;span class="c1"&gt;// This exposes your secret to every user's browser&lt;/span&gt;
&lt;span class="nx"&gt;NEXT_PUBLIC_DB_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;supersecret123&lt;/span&gt;
&lt;span class="nx"&gt;NEXT_PUBLIC_STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;sk_live_&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anything with &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; is &lt;strong&gt;visible to anyone who opens your site&lt;/strong&gt;. It gets embedded into the JavaScript bundle. DevTools. View Source. It's all there.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable Type&lt;/th&gt;
&lt;th&gt;Accessible In&lt;/th&gt;
&lt;th&gt;Exposed to Browser?&lt;/th&gt;
&lt;th&gt;Use For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NEXT_PUBLIC_*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Client + Server&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;API base URLs, public keys, analytics IDs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regular &lt;code&gt;ENV_VAR&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Server only&lt;/td&gt;
&lt;td&gt;NO&lt;/td&gt;
&lt;td&gt;DB passwords, secret keys, tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;process.env.NODE_ENV&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both&lt;/td&gt;
&lt;td&gt;NO (built-in)&lt;/td&gt;
&lt;td&gt;Environment detection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rule is simple: if it's a secret, it never gets &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt;. If it has to be on the client, it better not be a secret.&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.amazonaws.com%2Fuploads%2Farticles%2F28sbwh76o72cz20l8pcx.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.amazonaws.com%2Fuploads%2Farticles%2F28sbwh76o72cz20l8pcx.png" alt="Ahmer Shah" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. CORS Is Not a Bug. It's You.
&lt;/h3&gt;

&lt;p&gt;You've got Next.js running on port 3000. Your Node.js/Express backend is on port 3001. You make a fetch request. CORS error. You Google it. You find a Stack Overflow answer from 2019 that tells you to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The lazy "fix" everyone copies&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it works locally. So you push to production.&lt;/p&gt;

&lt;p&gt;And then in production it breaks again because the origin is different, or worse: it works but you've now allowed every single origin on the planet to make requests to your backend. Including people you don't want.&lt;/p&gt;

&lt;p&gt;Here's what actually correct CORS configuration looks like for a Next.js + Node.js setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Express backend - cors.config.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedOrigins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-actual-domain.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FRONTEND_URL&lt;/span&gt; &lt;span class="c1"&gt;// dynamic, set in .env&lt;/span&gt;
&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Allow requests with no origin (mobile apps, Postman, curl)&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allowedOrigins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CORS policy blocked this origin: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// if you're using cookies/sessions&lt;/span&gt;
  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DELETE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OPTIONS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;allowedHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&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;p&gt;And honestly? If you're already using Next.js, ask yourself whether you need a separate Express server at all. Next.js API routes handle a huge amount of backend logic without this CORS mess.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. You Don't Actually Know When to Use API Routes vs Express
&lt;/h3&gt;

&lt;p&gt;This is the architectural confusion that costs teams weeks.&lt;/p&gt;

&lt;p&gt;Next.js has built-in API routes (in &lt;code&gt;pages/api/&lt;/code&gt; or &lt;code&gt;app/api/route.ts&lt;/code&gt;). They run on Node.js. They're serverless by default when deployed to Vercel. They're fine for most things.&lt;/p&gt;

&lt;p&gt;But a lot of developers either:&lt;/p&gt;

&lt;p&gt;a) Build a whole Express.js server for things Next.js API routes would handle perfectly, creating unnecessary complexity and CORS problems.&lt;/p&gt;

&lt;p&gt;b) Cram everything into Next.js API routes when they actually need persistent connections, WebSockets, heavy background jobs, or something Vercel doesn't support well.&lt;/p&gt;

&lt;p&gt;Here's the honest comparison:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Next.js API Routes&lt;/th&gt;
&lt;th&gt;Separate Node.js/Express&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CRUD for your app's own data&lt;/td&gt;
&lt;td&gt;Perfect&lt;/td&gt;
&lt;td&gt;Overkill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication (JWT, sessions)&lt;/td&gt;
&lt;td&gt;Fine&lt;/td&gt;
&lt;td&gt;Unnecessary complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-time features (WebSockets)&lt;/td&gt;
&lt;td&gt;Not supported natively&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heavy file processing&lt;/td&gt;
&lt;td&gt;Cold starts are a problem&lt;/td&gt;
&lt;td&gt;Better&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared API between multiple frontends&lt;/td&gt;
&lt;td&gt;Awkward&lt;/td&gt;
&lt;td&gt;Right choice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microservices architecture&lt;/td&gt;
&lt;td&gt;Wrong tool&lt;/td&gt;
&lt;td&gt;Right tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background jobs / cron&lt;/td&gt;
&lt;td&gt;Limited (Vercel Cron has limits)&lt;/td&gt;
&lt;td&gt;Better&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long-running processes&lt;/td&gt;
&lt;td&gt;Hard timeout limits&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database connection pooling at scale&lt;/td&gt;
&lt;td&gt;Works but tricky&lt;/td&gt;
&lt;td&gt;More control&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you're building a standard web app with a database, auth, and CRUD — just use Next.js API routes. You don't need Express. You're adding complexity for no reason.&lt;/p&gt;

&lt;p&gt;If you're building something that needs persistent connections, serves multiple clients, runs heavy background jobs, or lives on a VM you control — separate Node.js server makes sense.&lt;/p&gt;

&lt;p&gt;Most developers I've seen choose the wrong one because they learned Express first and can't let it go.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Hardcoded URLs That Die in Production
&lt;/h3&gt;

&lt;p&gt;This one is so common it's almost a rite of passage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Works on your laptop, breaks everywhere else&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3001/api/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is hardcoded to localhost. When you deploy to Vercel or any server, &lt;code&gt;localhost:3001&lt;/code&gt; means nothing. There's no machine called localhost in production. The request goes nowhere.&lt;/p&gt;

&lt;p&gt;The fix isn't complicated. But you have to actually do it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In .env.local (for development)&lt;/span&gt;
&lt;span class="nx"&gt;NEXT_PUBLIC_API_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:3001&lt;/span&gt;

&lt;span class="c1"&gt;// In .env.production&lt;/span&gt;
&lt;span class="nx"&gt;NEXT_PUBLIC_API_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//api.yourdomain.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In your code&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_API_BASE_URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_BASE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/users`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you're using Next.js API routes as your backend (same app), you don't even need an absolute URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This works in both dev and production when backend = same Next.js app&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Relative URLs. Underrated. People overcomplicate this.&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.amazonaws.com%2Fuploads%2Farticles%2Fnk0kao0nhnw7lxelq7xv.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.amazonaws.com%2Fuploads%2Farticles%2Fnk0kao0nhnw7lxelq7xv.png" alt="Ahmer Shah" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Git Workflow for Full-Stack Projects Is Different and Nobody Talks About It
&lt;/h3&gt;

&lt;p&gt;In a typical single-technology project, Git workflow is straightforward. Feature branch, PR, merge. But in a Next.js + Node.js project where the frontend and backend are sometimes in the same repo and sometimes in different repos, things get messy fast.&lt;/p&gt;

&lt;p&gt;The two main patterns:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monorepo (same repo, both apps)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-project/
  ├── apps/
  │   ├── web/          (Next.js)
  │   └── api/          (Express.js)
  ├── packages/
  │   └── shared/       (shared types, utilities)
  └── package.json      (root, with workspaces)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Polyrepo (separate repos)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-project-frontend/    (Next.js)
my-project-backend/     (Express.js)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The mistake most junior developers make is none of the above. They put everything in one flat folder and commit everything together, so a frontend change and a backend change always get tangled in the same commit. Makes code review messy. Makes rollbacks a nightmare.&lt;/p&gt;

&lt;p&gt;And then there's branching. Here's what actually works for full-stack:&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;# Never commit directly to main&lt;/span&gt;
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; feature/user-authentication

&lt;span class="c"&gt;# Commit frequently with meaningful messages&lt;/span&gt;
&lt;span class="c"&gt;# Bad commit message:&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix stuff"&lt;/span&gt;

&lt;span class="c"&gt;# Good commit message:&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat(auth): add JWT validation middleware to /api/auth/verify

- Validates token expiry
- Returns 401 on invalid token
- Logs failed attempts to console (temporary)"&lt;/span&gt;

&lt;span class="c"&gt;# When done, push and open PR&lt;/span&gt;
git push origin feature/user-authentication
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The conventional commits standard (&lt;code&gt;feat:&lt;/code&gt;, &lt;code&gt;fix:&lt;/code&gt;, &lt;code&gt;chore:&lt;/code&gt;, &lt;code&gt;docs:&lt;/code&gt;, &lt;code&gt;refactor:&lt;/code&gt;) isn't just cosmetic. Tools like &lt;code&gt;semantic-release&lt;/code&gt; and automatic changelog generators depend on it. In 2026 with AI code review tools integrated into GitHub, structured commits also give the AI better context about what changed.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. The package-lock.json Civil War
&lt;/h3&gt;

&lt;p&gt;Every team eventually has this fight.&lt;/p&gt;

&lt;p&gt;One developer uses &lt;code&gt;npm install&lt;/code&gt;. Another uses &lt;code&gt;yarn add&lt;/code&gt;. A third one used &lt;code&gt;pnpm&lt;/code&gt; because they watched a YouTube video. Now you have &lt;code&gt;package-lock.json&lt;/code&gt;, &lt;code&gt;yarn.lock&lt;/code&gt;, and &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; all in the same repo. Three different lockfiles, three different dependency resolution algorithms, and production might be running a completely different version of a package than what's on your laptop.&lt;/p&gt;

&lt;p&gt;This is not a minor problem. Node.js's package ecosystem has had supply chain attacks where malicious code ended up in popular packages. Lockfiles are your defense mechanism. If everyone on the team is generating different lockfiles, the lockfile is meaningless.&lt;/p&gt;

&lt;p&gt;Pick one package manager. Enforce it. Delete the others.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"engines"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=22.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"npm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=10.0.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"packageManager"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm@10.8.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&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;&lt;span class="c"&gt;# .npmrc - to enforce no other package managers&lt;/span&gt;
engine-strict&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And commit your &lt;code&gt;package-lock.json&lt;/code&gt;. I know it's large. I know it creates merge conflicts. Commit it anyway. The moment you add it to &lt;code&gt;.gitignore&lt;/code&gt; you've thrown away reproducible builds.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. The .next Folder Is Not Source Code
&lt;/h3&gt;

&lt;p&gt;This is a smaller mistake but it's one of those things that adds up.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.next/&lt;/code&gt; is Next.js's build output folder. It's generated fresh every time you run &lt;code&gt;next build&lt;/code&gt; or &lt;code&gt;next dev&lt;/code&gt;. It's specific to your machine, your Node.js version, and your build configuration.&lt;/p&gt;

&lt;p&gt;Some developers commit it because they think it's needed. It's not. It should be in &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Folder&lt;/th&gt;
&lt;th&gt;Commit to Git?&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.next/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Build output, machine-specific&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;node_modules/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Never&lt;/td&gt;
&lt;td&gt;Installable from package.json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;out/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Usually no&lt;/td&gt;
&lt;td&gt;Static export output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;public/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Static assets served by app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;src/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Your actual source code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.env.local&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Never&lt;/td&gt;
&lt;td&gt;Local secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;next.config.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Configuration, not secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Committing &lt;code&gt;node_modules&lt;/code&gt; is the classic version of this mistake. Everyone learns it eventually. But &lt;code&gt;.next/&lt;/code&gt; and &lt;code&gt;out/&lt;/code&gt; catch more people than you'd think.&lt;/p&gt;




&lt;h3&gt;
  
  
  9. Nobody Configures next.config.js for Real Environments
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;next.config.js&lt;/code&gt; file is where a lot of important production behavior lives and most tutorials just skip it entirely.&lt;/p&gt;

&lt;p&gt;Here's a real example of things that break in production because they weren't configured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// next.config.js - what a real production config looks like&lt;/span&gt;

&lt;span class="cm"&gt;/** @type {import('next').NextConfig} */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Tell Next.js where your external API lives (for rewrites/proxying)&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;rewrites&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/backend/:path*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BACKEND_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/:path*`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="c1"&gt;// Image domains (or you get 400 errors on external images)&lt;/span&gt;
  &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;remotePatterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-image-cdn.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/images/**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="c1"&gt;// Environment variables you want to expose through Next.js config&lt;/span&gt;
  &lt;span class="c1"&gt;// (alternative to NEXT_PUBLIC_ prefix for build-time values)&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;APP_VERSION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;npm_package_version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="c1"&gt;// Strict mode - catches more React issues in dev&lt;/span&gt;
  &lt;span class="na"&gt;reactStrictMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="c1"&gt;// Output mode for deployment&lt;/span&gt;
  &lt;span class="c1"&gt;// 'standalone' is what you want for Docker/VPS deployment&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_OUTPUT_MODE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One that kills a lot of people: Next.js 15 (with App Router) handles rewrites differently from the Pages Router in some edge cases. If you're proxying requests to your Node.js backend through Next.js rewrites, test this in a staging environment that matches production. Vercel's serverless environment is not the same as &lt;code&gt;next start&lt;/code&gt; on a VPS.&lt;/p&gt;




&lt;h3&gt;
  
  
  10. The Deployment Split Nobody Plans For
&lt;/h3&gt;

&lt;p&gt;Here's the final one and it's the most expensive mistake in real projects.&lt;/p&gt;

&lt;p&gt;You build your app locally. Next.js and Node.js both run on your machine, communicate fine, everything works. Then you go to deploy. And someone (probably you) makes a decision without thinking about it:&lt;/p&gt;

&lt;p&gt;"I'll put the Next.js app on Vercel because it's free and easy."&lt;/p&gt;

&lt;p&gt;So your Next.js app is on Vercel, which is serverless, auto-scaling, edge-deployed.&lt;/p&gt;

&lt;p&gt;Your Node.js backend is on... a $5 DigitalOcean droplet. Or Railway. Or Render's free tier that spins down after 15 minutes of inactivity.&lt;/p&gt;

&lt;p&gt;Now you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Different deployment cadences&lt;/li&gt;
&lt;li&gt;Different environment variable management systems&lt;/li&gt;
&lt;li&gt;Cold start latency on one side but not the other&lt;/li&gt;
&lt;li&gt;CORS configuration that has to be updated every time the domain changes&lt;/li&gt;
&lt;li&gt;Two separate CI/CD pipelines to maintain&lt;/li&gt;
&lt;li&gt;Your Node.js backend hitting cold starts on the free tier, making your Vercel frontend look slow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nobody planned this. It happened by accident. And now you're refactoring three months into the project.&lt;/p&gt;

&lt;p&gt;The planning question you have to answer before writing a line of code:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Frontend&lt;/th&gt;
&lt;th&gt;Backend&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hobby project, low traffic&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;Vercel (API Routes only)&lt;/td&gt;
&lt;td&gt;One deployment, no CORS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medium app, budget matters&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;Railway / Render&lt;/td&gt;
&lt;td&gt;Plan for cold starts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serious production app&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;VPS (DigitalOcean, Hetzner)&lt;/td&gt;
&lt;td&gt;Most control, more work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full control / enterprise&lt;/td&gt;
&lt;td&gt;VPS (Docker)&lt;/td&gt;
&lt;td&gt;VPS (same or different)&lt;/td&gt;
&lt;td&gt;You manage everything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monorepo, full stack&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;Vercel (both)&lt;/td&gt;
&lt;td&gt;Works if serverless is fine&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What the Actually Good Developers Do That Nobody Posts About
&lt;/h2&gt;

&lt;p&gt;I've worked with and observed enough codebases at this point to notice the difference. Here's what separates developers who get this right:&lt;/p&gt;

&lt;p&gt;They &lt;strong&gt;set up the project structure before writing the first component&lt;/strong&gt;. &lt;code&gt;.gitignore&lt;/code&gt;, environment variable schema, API base URL configuration — all before &lt;code&gt;git init&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;They &lt;strong&gt;test environment variable loading in isolation&lt;/strong&gt;. Before wiring up any API call, they &lt;code&gt;console.log(process.env.WHATEVER)&lt;/code&gt; in the actual runtime context where it'll be used. Server component? Client component? API route? They verify.&lt;/p&gt;

&lt;p&gt;They &lt;strong&gt;use a &lt;code&gt;.env.example&lt;/code&gt; file&lt;/strong&gt; committed to the repo that shows every variable needed without the values. This is how you tell your team what to configure without leaking anything.&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;# .env.example (COMMIT THIS)&lt;/span&gt;
&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql://user:password@host:port/database
&lt;span class="nv"&gt;NEXTAUTH_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;generate-with-openssl-rand-base64-32
&lt;span class="nv"&gt;NEXTAUTH_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:3000
&lt;span class="nv"&gt;BACKEND_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:3001
&lt;span class="nv"&gt;NEXT_PUBLIC_API_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:3001

&lt;span class="c"&gt;# Production values go in your deployment platform's environment settings&lt;/span&gt;
&lt;span class="c"&gt;# NEVER commit .env.local or .env.production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They &lt;strong&gt;treat Git history as documentation&lt;/strong&gt;. Not just for code review. When something breaks in production six months later, a good commit history lets you bisect the problem in minutes instead of hours.&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;# Binary search through commits to find when a bug was introduced&lt;/span&gt;
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
&lt;span class="c"&gt;# Git checks out the middle commit, you test it&lt;/span&gt;
&lt;span class="c"&gt;# Then mark good or bad until you find the exact commit&lt;/span&gt;
git bisect good  &lt;span class="c"&gt;# or git bisect bad&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They &lt;strong&gt;never debate whether to use the App Router or Pages Router in 2026&lt;/strong&gt;. The App Router is the default, it's stable, React Server Components are the future of this ecosystem. If you're starting a new project today and using Pages Router you're actively choosing to work with a deprecated pattern. That's a choice you're allowed to make but be honest that it's a choice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Spicy Take: The Real Problem Is Tutorials, Not Developers
&lt;/h2&gt;

&lt;p&gt;Okay I'm going to say this and people are going to disagree with me.&lt;/p&gt;

&lt;p&gt;The reason 90% of developers get this wrong isn't stupidity or laziness. It's the tutorial industry.&lt;/p&gt;

&lt;p&gt;A YouTube tutorial on "Build a Full Stack App with Next.js and Node.js" has a 43-minute runtime. The first 38 minutes is features. The last 5 minutes is "and now deploy it to Vercel." The &lt;code&gt;.gitignore&lt;/code&gt; setup takes 30 seconds and is either done off-camera or copied from a template without explanation. Environment variables are hardcoded for simplicity. CORS is fixed with &lt;code&gt;app.use(cors())&lt;/code&gt; and nobody explains why.&lt;/p&gt;

&lt;p&gt;Millions of developers learned from those tutorials. And then they went to build real things with those patterns and ran into real problems.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The documentation tells you what the tools do. It rarely tells you what happens when you misuse them in combination."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That gap between "I finished the tutorial" and "I can build real production software" is where most developers are stuck. And the combination of Next.js, Node.js, and Git is exactly where that gap shows up most violently.&lt;/p&gt;




&lt;h2&gt;
  
  
  The One Thing That Would Fix 80% of These Problems
&lt;/h2&gt;

&lt;p&gt;It's embarrassingly simple.&lt;/p&gt;

&lt;p&gt;Start every project with this:&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;# 1. Initialize git FIRST, before anything else&lt;/span&gt;
git init my-project
&lt;span class="nb"&gt;cd &lt;/span&gt;my-project

&lt;span class="c"&gt;# 2. Create .gitignore BEFORE adding any files&lt;/span&gt;
&lt;span class="c"&gt;# Copy the one from the Node + Next.js section above&lt;/span&gt;

&lt;span class="c"&gt;# 3. Create .env.example&lt;/span&gt;
&lt;span class="nb"&gt;touch&lt;/span&gt; .env.example
&lt;span class="c"&gt;# Write out all the variables your app will need (empty values)&lt;/span&gt;

&lt;span class="c"&gt;# 4. Create .env.local for your actual local values&lt;/span&gt;
&lt;span class="c"&gt;# (This is already in .gitignore so it won't be committed)&lt;/span&gt;

&lt;span class="c"&gt;# 5. THEN scaffold your Next.js app&lt;/span&gt;
npx create-next-app@latest &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--typescript&lt;/span&gt;

&lt;span class="c"&gt;# 6. First commit should be: gitignore + env.example + nothing else&lt;/span&gt;
git add .gitignore .env.example README.md
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"chore: project initialization with gitignore and env template"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sequence. In that order. If every new developer starting a Next.js project followed those six steps in that order, the number of accidental secret exposures would drop dramatically.&lt;/p&gt;

&lt;p&gt;The order matters because once you run &lt;code&gt;create-next-app&lt;/code&gt;, you're tempted to immediately start building. And in that excitement, you forget to check what's actually being staged when you do &lt;code&gt;git add .&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Data Snapshot: Where This Stack Is in 2026
&lt;/h2&gt;

&lt;p&gt;Some numbers that give context to why this matters at scale:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js remains the dominant React meta-framework by weekly npm downloads (consistently above 5.8M per week through Q1 2026)&lt;/li&gt;
&lt;li&gt;Node.js 22 LTS is the current recommended version as of early 2026; Node.js 24 released April 2025 is on a path to LTS in October 2026&lt;/li&gt;
&lt;li&gt;Git is used by 97.8% of developers in the Stack Overflow Developer Survey 2025 — effectively universal&lt;/li&gt;
&lt;li&gt;The State of JavaScript 2024 survey showed Next.js with 81% retention (developers who used it and would use it again) and rising adoption year-over-year&lt;/li&gt;
&lt;li&gt;GitHub's transparency report data for 2024 indicated that secrets scanning blocked millions of exposures before they became public — meaning the push-protection feature is catching the exact mistakes described in this article&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The scale of adoption means these mistakes aren't happening to a few developers. They're happening tens of thousands of times a day, globally, by people across all experience levels.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Questions That Don't Have Good Answers Online
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"Should I use Next.js API routes or a separate Express server for a startup?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're building a startup MVP, use Next.js API routes. You'll ship faster and you have one less deployment to manage. When you hit actual scaling problems, migrate. You won't hit those problems as early as you think.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Does it matter if node_modules gets committed once?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. &lt;code&gt;node_modules&lt;/code&gt; can be hundreds of megabytes. It bloats your repository permanently (remember, Git keeps history). And it creates reproducibility problems. Delete it from history using &lt;code&gt;git filter-repo&lt;/code&gt; the same way you'd remove a secret.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"What's the right Node.js version to use with Next.js 15?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Node.js 18 is the minimum for Next.js 15. Node.js 22 LTS is what you should be using in production as of early 2026. The compatibility table on the Next.js docs is up to date and should be your source of truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Why does my Next.js app work on Vercel but my environment variables are undefined?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because you configured them in &lt;code&gt;.env.local&lt;/code&gt; on your machine but forgot to add them to Vercel's environment variable settings in the dashboard. Vercel does not read your &lt;code&gt;.env.local&lt;/code&gt;. You have to set every variable manually in the Vercel project settings. This trips up everyone once.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;The combination of Next.js, Node.js, and Git is genuinely powerful. The ecosystem in 2026 is mature enough that you can build serious production applications with it and compete with teams twice your size.&lt;/p&gt;

&lt;p&gt;But "powerful" and "forgiving" are different things. This stack is not forgiving. It will let you push your &lt;code&gt;.env&lt;/code&gt; to GitHub. It will silently give you &lt;code&gt;undefined&lt;/code&gt; instead of your secret key. It will deploy with broken environment variables and give you no useful error message at 2am.&lt;/p&gt;

&lt;p&gt;The developers who get this right aren't necessarily more talented. They've just been burned once and learned from it, or they were lucky enough to learn from someone who was burned.&lt;/p&gt;

&lt;p&gt;Now you've read about it instead of having to live through it.&lt;/p&gt;

&lt;p&gt;Use that.&lt;/p&gt;




&lt;h2&gt;
  
  
  References and Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;GitHub Security: "Detected and Prevented Secrets in 2024" — GitHub Blog, January 2025. &lt;a href="https://github.blog/security/application-security/" rel="noopener noreferrer"&gt;https://github.blog/security/application-security/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stack Overflow Developer Survey 2025 — Version Control Systems usage data. &lt;a href="https://survey.stackoverflow.co/2025" rel="noopener noreferrer"&gt;https://survey.stackoverflow.co/2025&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;State of JavaScript 2024 — Meta-Frameworks section, Next.js retention and usage figures. &lt;a href="https://2024.stateofjs.com/" rel="noopener noreferrer"&gt;https://2024.stateofjs.com/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next.js 15 Release Notes and Changelog — Vercel/Next.js GitHub repository. &lt;a href="https://github.com/vercel/next.js/releases/tag/v15.0.0" rel="noopener noreferrer"&gt;https://github.com/vercel/next.js/releases/tag/v15.0.0&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Node.js Release Schedule — Node.js Foundation. &lt;a href="https://nodejs.org/en/about/previous-releases" rel="noopener noreferrer"&gt;https://nodejs.org/en/about/previous-releases&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;npm package download statistics for &lt;code&gt;next&lt;/code&gt; — &lt;a href="https://www.npmjs.com/package/next" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/next&lt;/a&gt; (weekly download trends, 2024-2026)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next.js Documentation: Environment Variables — &lt;a href="https://nextjs.org/docs/app/building-your-application/configuring/environment-variables" rel="noopener noreferrer"&gt;https://nextjs.org/docs/app/building-your-application/configuring/environment-variables&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next.js Documentation: API Routes — &lt;a href="https://nextjs.org/docs/pages/building-your-application/routing/api-routes" rel="noopener noreferrer"&gt;https://nextjs.org/docs/pages/building-your-application/routing/api-routes&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conventional Commits Specification v1.0.0 — &lt;a href="https://www.conventionalcommits.org/" rel="noopener noreferrer"&gt;https://www.conventionalcommits.org/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;git-filter-repo documentation — &lt;a href="https://github.com/newren/git-filter-repo" rel="noopener noreferrer"&gt;https://github.com/newren/git-filter-repo&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OWASP Secrets Management Cheat Sheet — &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" rel="noopener noreferrer"&gt;https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vercel Deployment Environment Variables Guide — &lt;a href="https://vercel.com/docs/projects/environment-variables" rel="noopener noreferrer"&gt;https://vercel.com/docs/projects/environment-variables&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;This article reflects my actual experience debugging these issues in real codebases. The mistakes described are patterns I've seen repeatedly, not edge cases. If something here contradicts what you've been doing, that's not an accident.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Find me across the web:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>git</category>
      <category>nextjs</category>
      <category>node</category>
    </item>
    <item>
      <title>Will AI Replace Software Engineers? No. But It Will Shrink Junior Roles.</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Wed, 03 Jun 2026 14:57:05 +0000</pubDate>
      <link>https://dev.to/syedahmershah/will-ai-replace-software-engineers-no-but-it-will-shrink-junior-roles-45lg</link>
      <guid>https://dev.to/syedahmershah/will-ai-replace-software-engineers-no-but-it-will-shrink-junior-roles-45lg</guid>
      <description>&lt;p&gt;Note: To stay fully transparent with the community, I want to share that I used AI assistance to help draft and polish this article. I’ve reviewed and edited everything to ensure it aligns with community guidelines and brings genuine value to you all!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And if you think you have time to "wait and see," you really, really don't.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Let me tell you about a friend of mine. Seven years of experience. Mid-level engineer. $190K total comp at a solid company — a Series B startup, let's not get sidetracked with names. He got laid off in early 2025. It happens. He had a strong GitHub profile, could do system design in his sleep, had a clean resume that would've cleared any screen two years ago. He got to final rounds at three different companies.&lt;/p&gt;

&lt;p&gt;Lost all three.&lt;/p&gt;

&lt;p&gt;The feedback, each time, was some version of the same sentence: &lt;em&gt;"We went with someone who was more fluent with AI tools."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;He wasn't anti-AI. He used Copilot sometimes. He wasn't one of those "real engineers write real code" types. He just hadn't gone deep on it. &lt;em&gt;Sometimes&lt;/em&gt; was enough — until suddenly it wasn't. The bar had moved and nobody sent him a memo.&lt;/p&gt;

&lt;p&gt;That story is not unique. Right now, as you're reading this in 2026, that exact story is playing out for tens of thousands of engineers across every level, every stack, every timezone. And here's the part that makes it worse: it's not slowing down. It's accelerating.&lt;/p&gt;

&lt;p&gt;Let's look at what's actually happening.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Numbers Don't Care About Your Feelings
&lt;/h2&gt;

&lt;p&gt;A lot of engineers are still operating on vibes. They hear "AI won't replace developers," breathe out, and go back to writing CRUD endpoints like nothing changed. I get it. But let's stop going on vibes for a second and look at what the data says.&lt;/p&gt;

&lt;p&gt;American tech companies eliminated more than 142,000 jobs in just the first five months of 2026 — a 33% increase over the same period the year before — even while those same employers were posting record revenues and committing to the largest infrastructure buildout in tech history, according to tech layoff trackers. Read that again. Record revenues. More layoffs. The math only makes sense when you understand what's actually driving it.&lt;/p&gt;

&lt;p&gt;The Stanford HAI 2026 AI Index, drawing on research from the Stanford Digital Economy Lab, found that early-career workers aged 22 to 25 in AI-exposed occupations experienced a 13% relative decline in employment since late 2022. Among 22-to-25-year-old software developers specifically, employment fell nearly 20% from its late 2022 peak by July 2025.&lt;/p&gt;

&lt;p&gt;Twenty percent. Gone. Not during a recession. Not because the industry slowed down. During a period of AI investment unlike anything we've ever seen.&lt;/p&gt;

&lt;p&gt;And here's the part that should genuinely bother you: for workers aged 30 and over in the highest AI-exposure categories, employment actually &lt;em&gt;grew&lt;/em&gt; between 6% and 12% over the same period. AI isn't destroying engineering as a profession. It's pulling up the floor. The junior layer is disappearing while the senior layer holds firm or grows. That is a very specific, very surgical thing happening.&lt;/p&gt;

&lt;p&gt;Entry-level postings dropped 60% between 2022 and 2024. Google and Meta are hiring roughly 50% fewer new grads compared to their 2021 peaks. According to Indeed's labour market data, software engineering listings are down approximately 35% from pre-pandemic levels — and roughly 70% from their 2022 peak.&lt;/p&gt;

&lt;p&gt;Seventy percent from peak.&lt;/p&gt;

&lt;p&gt;Think about what that means for a CS student graduating right now. Their professors built careers on a hiring market that simply doesn't exist anymore.&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.amazonaws.com%2Fuploads%2Farticles%2Fyswzn004nfbllqd1dni6.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.amazonaws.com%2Fuploads%2Farticles%2Fyswzn004nfbllqd1dni6.png" alt="a graphic showing a eye pyramid and rounded table" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The CEOs Stopped Being Diplomatic
&lt;/h2&gt;

&lt;p&gt;There used to be a script. "AI will create new jobs." "We're augmenting, not replacing." Every earnings call, every keynote, the same careful language. That script is mostly gone now.&lt;/p&gt;

&lt;p&gt;Marc Benioff, CEO of Salesforce — San Francisco's largest private employer — got on an earnings call in early 2025 and said it plainly: &lt;em&gt;"We're not going to hire any new engineers this year. We're seeing a 30% productivity increase in engineering, and we're going to really continue to ride that up."&lt;/em&gt;&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Zero new engineers. At one of the biggest enterprise software companies on Earth. Because AI made the existing team 30% more productive. Why hire ten people when seven get you the same output?&lt;/p&gt;

&lt;p&gt;But the line that deserves to be carved into the wall of every CS department in every university was this one, from the same call:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"My message to CEOs right now is that we are the last generation to manage only humans."&lt;/em&gt;&lt;br&gt;
— Marc Benioff, CEO of Salesforce, Q4 FY2025 Earnings Call&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's not some fringe tech provocateur being edgy for an audience. That's the CEO of a $145 billion company saying the quiet part loud, on a call with investors and analysts. That's the actual strategy being announced.&lt;/p&gt;

&lt;p&gt;Then there's Zuckerberg. On the Joe Rogan Experience in January 2025, he said something that didn't get nearly enough attention:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Probably in 2025, we at Meta, as well as the other companies that are basically working on this, are going to have an AI that can effectively be a sort of midlevel engineer that you have at your company that can write code."&lt;/em&gt;&lt;br&gt;
— Mark Zuckerberg, Joe Rogan Experience, January 2025&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Did that prediction land perfectly? Depends who you ask. But what isn't debatable is that Meta's junior developer hiring shrank dramatically through 2024 and 2025. The vision was stated. The hiring decisions followed.&lt;/p&gt;

&lt;p&gt;At Google, the numbers tell a story that keeps accelerating. Sundar Pichai first disclosed the 25% figure on the Q3 2024 earnings call.&lt;sup id="fnref3"&gt;3&lt;/sup&gt; By April 2025 it had climbed past 30%. By late 2025, Google's own CFO was citing "nearly half." Then, at Google Cloud Next 2026 in Las Vegas — just weeks ago — Pichai said this out loud:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Today, 75% of all new code at Google is now AI-generated and approved by engineers, up from 50% last fall."&lt;/em&gt;&lt;br&gt;
— Sundar Pichai, Google Cloud Next 2026, April 22, 2026&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Three-quarters of the codebase at one of the world's premier engineering organisations. Not written by a human hand.&lt;/p&gt;

&lt;p&gt;Satya Nadella, at Microsoft Build 2025, put Microsoft's comparable figure at around 30%.&lt;sup id="fnref4"&gt;4&lt;/sup&gt; That number has likely moved too.&lt;/p&gt;

&lt;p&gt;Let that trajectory sink in. The most influential software company on the planet just told the world, publicly, that three in four lines of new code it ships were generated by AI. Not as a confession. As a boast.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Klarna Story Nobody Wants to Sit With
&lt;/h2&gt;

&lt;p&gt;I keep coming back to Klarna because people draw the wrong lesson from it every single time.&lt;/p&gt;

&lt;p&gt;Between 2022 and 2024, Klarna reduced its workforce — cutting approximately 700 positions — while deploying AI to handle the volume those roles had covered: customer service, operations, repetitive backend work. CEO Sebastian Siemiatkowski was open about it. Then things went wrong. Customer complaints climbed. Service quality dropped. Siemiatkowski publicly acknowledged that the AI-driven transition had negatively affected service and product quality. By 2025, Klarna was rehiring human staff.&lt;/p&gt;

&lt;p&gt;People love this story. "See? AI failed. Humans win. Everyone goes home."&lt;/p&gt;

&lt;p&gt;But here's what everyone skips over: those 700 people lost one to two years of income. Some pivoted careers entirely. Others are still looking. When Klarna came back to rehire, they didn't rebuild what they had. They built something smaller, leaner, structured around a gig-style model that requires fewer permanent headcount. The company rolled back the &lt;em&gt;pace&lt;/em&gt; of replacement — not the &lt;em&gt;direction&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The lesson from Klarna is not "AI will fail so we're safe."&lt;/p&gt;

&lt;p&gt;The lesson from Klarna is this: companies will try to replace you with AI. Sometimes it'll backfire badly. When they course-correct, they'll hire back fewer people than they let go. The reset doesn't go home. It goes to a new, lower, permanent baseline.&lt;/p&gt;

&lt;p&gt;That's not a comfort. That's a warning.&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.amazonaws.com%2Fuploads%2Farticles%2Fasc1pn4jeh738lgkg3yb.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.amazonaws.com%2Fuploads%2Farticles%2Fasc1pn4jeh738lgkg3yb.png" alt="Visual Animation depicting difference between traditional developer" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Split That's Already Happening
&lt;/h2&gt;

&lt;p&gt;Here's what I'm actually seeing in the developer community right now, and it is not subtle.&lt;/p&gt;

&lt;p&gt;There are engineers who went all in — integrated AI tools into their workflows, learned the failure modes, used them to ship faster. A 2025 Microsoft/GitHub study found that engineers using Copilot completed comparable tasks 55% faster.&lt;sup id="fnref5"&gt;5&lt;/sup&gt; That productivity multiplier has translated directly into smaller junior headcounts at companies like Meta, Google, and hundreds of mid-size SaaS companies that right-sized their engineering organisations through 2024–2025. The engineers using AI well aren't just surviving — they're getting the promotions, the offers, the raises. By Q1 2025, 82% of developers reported using AI tools weekly, with 59% running three or more simultaneously. And the pay reflects it: AI-fluent developers are landing entry-level roles at $90K–$130K versus $65K–$85K for traditional profiles, according to job market data.&lt;/p&gt;

&lt;p&gt;Then there's the other group. Engineers who say "I don't trust AI code" or "it's glorified autocomplete" or — and I've heard this more than once — "real engineers write real code." Look, I understand the psychology. There's something genuinely uncomfortable about watching a tool do a significant portion of work you spent years learning. It feels like a betrayal of the craft.&lt;/p&gt;

&lt;p&gt;But the market has no feelings about your feelings about the craft.&lt;/p&gt;

&lt;p&gt;Take something like this — the kind of endpoint a junior developer used to spend a morning on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsonify&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;require_auth&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/users/&amp;lt;int:user_id&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nd"&gt;@require_auth&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;User not found&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_dict&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/users&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nd"&gt;@require_auth&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Email required&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_dict&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub Copilot or Claude Code generates something like that in about four seconds. With tests. With error handling. With docstrings if you ask. The junior developer who spent a career building this kind of muscle is now competing against a tool that does it in seconds.&lt;/p&gt;

&lt;p&gt;The job of writing this code isn't gone. The &lt;em&gt;reason to hire someone specifically to write this code&lt;/em&gt; absolutely is.&lt;/p&gt;

&lt;p&gt;What's not gone: knowing &lt;em&gt;why&lt;/em&gt; this architecture might be wrong for your specific use case. Knowing when to break the pattern. Understanding what happens when this hits 100,000 concurrent requests. That's senior engineer judgment. And AI, as of 2026, is still genuinely bad at it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The World Is Treating This Differently Than You Are
&lt;/h2&gt;

&lt;p&gt;Here's something that struck me hard: the institutions that usually move the slowest — governments — are scrambling faster than most individual developers I know.&lt;/p&gt;

&lt;p&gt;The U.S. has provided funding for AI certifications for 120,000 laid-off workers. Across Europe, AI retraining enrolments jumped 39%. Singapore has baked workforce AI transition programs directly into its national strategy. The WEF's Reskilling Revolution initiative has mobilised commitments expected to reach over 856 million people globally by 2030.&lt;sup id="fnref6"&gt;6&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;India — which has the world's largest pool of software developers — is doing something particularly interesting. Rather than panic about AI consuming developer jobs, India is systematically working to ensure its developers are the ones &lt;em&gt;building&lt;/em&gt; the AI. A NASSCOM report projects India's AI talent pool to double from 6.5 lakh to over 12.5 lakh professionals by 2027, growing at 15% year-on-year. In the past three years alone, 8.65 lakh candidates were trained in emerging tech, with 3.20 lakh specifically in AI and Big Data Analytics.&lt;sup id="fnref7"&gt;7&lt;/sup&gt; That's not a country in denial. That's a country repositioning at scale.&lt;/p&gt;

&lt;p&gt;The WEF's Future of Jobs Report 2025 puts the global picture in stark terms: by 2030, job disruption could affect 22% of all roles globally — displacing 92 million jobs while creating 170 million new ones.&lt;sup id="fnref6"&gt;6&lt;/sup&gt; Net positive on paper. Except the 92 million displaced are largely doing specific things: entry-level coding, repetitive testing, documentation, basic customer support. And the 170 million new jobs are in AI oversight, system architecture, ML infrastructure, AI safety, and technical leadership.&lt;/p&gt;

&lt;p&gt;The math is brutal in its simplicity. If you're a developer who primarily does the work AI now generates, you're in the 92 million. If you learn to architect systems, supervise AI output, and build what AI can't build alone — you're in the 170 million.&lt;/p&gt;

&lt;p&gt;Every country that's paying attention is trying to get into the 170 million. Are you?&lt;/p&gt;




&lt;h2&gt;
  
  
  What AI Is Actually Taking (And It's Not What You Think)
&lt;/h2&gt;

&lt;p&gt;Let me be precise about the mechanism here, because the discourse is sloppy and sloppy thinking leads to wrong decisions.&lt;/p&gt;

&lt;p&gt;AI is not replacing software engineering as a discipline. The judgment, the architecture, the systems thinking, the ability to navigate technical debt and organisational complexity — that's not going anywhere soon. What AI &lt;em&gt;is&lt;/em&gt; replacing are the specific tasks that junior developers were hired to do: boilerplate, basic CRUD, scripted testing, routine bug fixes, first-draft documentation.&lt;/p&gt;

&lt;p&gt;The problem is, those weren't just tasks.&lt;/p&gt;

&lt;p&gt;They were the apprenticeship. You wrote the boilerplate and slowly started to understand &lt;em&gt;why&lt;/em&gt; the boilerplate worked. You fixed the simple bugs and developed an intuition for reading unfamiliar code. You built the CRUD endpoints and gradually developed a feel for data modelling. You did the repetitive work and, somewhere in that repetition, you became an engineer who could do the hard work.&lt;/p&gt;

&lt;p&gt;That entire training pipeline is now compressed or closed. Companies are skipping the junior layer and hiring mid-to-senior engineers who can direct and supervise AI output. The most visible effect of AI coding tools in 2026 isn't eliminating senior engineers — it's hollowing out the layer below them. Companies that used to run 3–5 juniors per senior are now running leaner teams.&lt;/p&gt;

&lt;p&gt;AWS CEO Matt Garman said it directly, calling the strategy of simply eliminating the junior layer &lt;em&gt;"one of the dumbest things I've ever heard"&lt;/em&gt; — warning that companies risk creating a catastrophic skills gap over the next decade. If you wipe out the apprenticeship, you stop producing the next generation of senior engineers.&lt;/p&gt;

&lt;p&gt;He's right.&lt;/p&gt;

&lt;p&gt;And most companies are doing it anyway, because short-term cost savings beat long-term talent pipeline thinking every single quarter. That's not cynicism. That's just how publicly traded companies behave.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You're Actually Supposed to Do
&lt;/h2&gt;

&lt;p&gt;Okay, I've been pretty dark. Let me be useful for a second, because fear without action is just anxiety.&lt;/p&gt;

&lt;p&gt;The engineers I see doing well right now share a few specific things.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They treat AI like a junior developer, not an oracle.&lt;/strong&gt; They use it to generate first drafts and review those drafts with the same critical eye they'd apply to a first-year intern's pull request. They understand &lt;em&gt;why&lt;/em&gt; the AI generated what it generated — which means they catch when it's confidently wrong. They have architectural opinions that the AI cannot substitute for.&lt;/p&gt;

&lt;p&gt;The practical workflow looks something like this:&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;# How senior engineers are actually working in 2026&lt;/span&gt;

&lt;span class="c"&gt;# Step 1: You design the architecture — AI is genuinely bad at this&lt;/span&gt;
&lt;span class="c"&gt;# Step 2: AI scaffolds the implementation&lt;/span&gt;
&lt;span class="c"&gt;# Step 3: You review critically and catch the failure modes&lt;/span&gt;

&lt;span class="c"&gt;# Example — prompting Claude Code or Cursor:&lt;/span&gt;
&lt;span class="c"&gt;# "Create a rate-limiter middleware for our Express API&lt;/span&gt;
&lt;span class="c"&gt;#  using Redis, with per-user and per-IP limits,&lt;/span&gt;
&lt;span class="c"&gt;#  with proper fallback handling for Redis connection failures"&lt;/span&gt;

&lt;span class="c"&gt;# AI gets ~80% right immediately&lt;/span&gt;
&lt;span class="c"&gt;# The remaining 20% — Redis failover edge cases,&lt;/span&gt;
&lt;span class="c"&gt;# production-specific config, security gaps — YOU catch that&lt;/span&gt;
&lt;span class="c"&gt;# That gap is the job now. That's your value.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;They have strong opinions about system design.&lt;/strong&gt; When to use microservices versus a monolith. When a message queue adds value and when it just adds complexity. How to handle distributed transactions. When to cache — and when caching creates more problems than it solves. This is the domain where experience lives and AI doesn't, because it requires judgment shaped by having built things that broke in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They know exactly where AI fails.&lt;/strong&gt; Not vaguely ("AI makes mistakes") but specifically: hallucinated API calls that look correct until they don't. Security vulnerabilities in generated authentication code. Incorrect business logic assumptions baked silently into generated functions. Only about 30% of AI-suggested code gets accepted by developers who actually know what to look for — and that selectivity is itself a skill you have to develop. The developers doing well right now have built a detailed personal map of where AI goes wrong.&lt;/p&gt;

&lt;p&gt;Here's the clearest way I can put the distinction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# AI generates this in seconds — low value in knowing it by heart
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_by_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# AI cannot answer these for you — this is where your career lives:
# → Why PostgreSQL over MongoDB for this specific use case?
# → How does this query behave under 10,000 concurrent requests?
# → What are the GDPR implications of storing this email field?
# → When do you add a Redis cache here, and when is it overkill?
# → How does this endpoint interact with your circuit breaker?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That second list. That's the job now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They're building in public.&lt;/strong&gt; Writing about what they're learning, contributing to open source, creating content that makes their &lt;em&gt;thinking&lt;/em&gt; visible. When AI can replicate anyone's code sample, the hiring signal shifts to judgment. The developers getting offers right now are the ones whose judgment is legible from the outside — you can read who they are from their GitHub, their articles, their opinions on hard problems.&lt;/p&gt;

&lt;p&gt;And the ones who are most secure? They understand the business too. AI is making pure technical skills cheaper every month. What it cannot replicate is the engineer who deeply understands the domain, speaks the language of product and business, can talk to customers, can translate between the technical and the strategic. That profile — technically sharp &lt;em&gt;and&lt;/em&gt; business-fluent — is more valuable right now than it has been at any point in the last decade.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Criticism That Needs to Be Said
&lt;/h2&gt;

&lt;p&gt;Something unpopular needs to be said.&lt;/p&gt;

&lt;p&gt;A lot of the "AI won't replace developers" discourse is being driven by people with significant financial or psychological incentives to believe it. Senior engineers who don't want to feel their skills are devaluing. Bootcamp founders who need enrolment. CS departments whose own enrolment is already dropping. VCs who've bet on human-in-the-loop products.&lt;/p&gt;

&lt;p&gt;None of these people are lying exactly. But they're all reading the same data through a very interested filter.&lt;/p&gt;

&lt;p&gt;U.S. Bureau of Labor Statistics data shows software developer employment fell 27.5% between 2023 and 2025.&lt;sup id="fnref8"&gt;8&lt;/sup&gt; A Resume.org survey of 1,000 U.S. business leaders found that six in ten companies are likely to lay off employees in 2026, with four in ten planning to specifically replace workers with AI.&lt;sup id="fnref9"&gt;9&lt;/sup&gt; These are not rounding errors. These are not post-pandemic corrections. These are structural shifts.&lt;/p&gt;

&lt;p&gt;When critics say "but AI code is buggy, it needs human review, it can't handle complex systems" — they're not wrong. But they're imagining a binary: either AI replaces engineers completely or nothing changes. Reality is a third option, the one that's already here: AI replaces specific tasks within engineering, shrinks team sizes, raises the floor of what gets you hired, and leaves a smaller but more capable group of engineers doing work that genuinely requires human judgment.&lt;/p&gt;

&lt;p&gt;That third option arrived while people were still debating whether the first one was possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Resume Has to Look Like Now
&lt;/h2&gt;

&lt;p&gt;Two years ago, a junior developer posting read: "1–2 years experience, proficiency in React and Node, familiar with Git."&lt;/p&gt;

&lt;p&gt;Today — if a junior posting exists at all, and there are far fewer — it reads something closer to: "Experience with AI-assisted development workflows, ability to review and validate AI-generated code, familiarity with prompt engineering for code generation, experience with at least two AI coding tools."&lt;/p&gt;

&lt;p&gt;Entry-level hiring at the 15 biggest tech firms fell 25% from 2023 to 2024, according to a SignalFire report.&lt;sup id="fnref10"&gt;10&lt;/sup&gt; Employers' rating of the market for college graduates is at its most pessimistic since 2020, per NACE's Job Outlook 2026.&lt;sup id="fnref11"&gt;11&lt;/sup&gt; With AI performing more of the grunt work that used to be the entry-level on-ramp, expectations for new grads have shifted dramatically upward. You're expected to show up already knowing things that used to be learned on the job.&lt;/p&gt;

&lt;p&gt;If you're graduating this year, or seriously thinking about entering the field — the playbook has fundamentally changed. You cannot follow the path that produced the engineers who might be mentoring you. Their path, the one that started with two years of boilerplate and slowly accumulated into expertise, is largely gone.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bet That's Already Been Made
&lt;/h2&gt;

&lt;p&gt;Here's the context I don't see enough people connecting to the rest of this.&lt;/p&gt;

&lt;p&gt;Tech companies globally are committing to a combined $700 billion in AI infrastructure investment. Jensen Huang put it directly: &lt;em&gt;"One trillion dollars of AI infrastructure is coming. The entire installed base of data centers will be renewed."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Companies don't bet that kind of money on something they think might fizzle. This is the largest concentrated capital commitment in tech history — bigger than the cloud transition, bigger than mobile. And every dollar of it is simultaneously a bet that AI will replace significant volumes of human cognitive labour, including coding labour.&lt;/p&gt;

&lt;p&gt;The companies making that bet are also the companies deciding who to hire. When Amazon, Microsoft, Google, and Meta collectively commit hundreds of billions to AI infrastructure, they are making a simultaneous workforce decision: fewer junior developers, more ML engineers, more people who build and maintain the systems that will do what humans used to do.&lt;/p&gt;

&lt;p&gt;This is not a hiring cycle. This is a structural transformation. And the decision was made years ago. We're just living in the consequences.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Question Worth Actually Sitting With
&lt;/h2&gt;

&lt;p&gt;Here's something I'd encourage every working developer to honestly answer for themselves.&lt;/p&gt;

&lt;p&gt;If your job title stayed exactly the same, but all the junior tasks — the boilerplate, the tests, the first-draft implementations — were offloaded to AI, what would you actually be doing all day?&lt;/p&gt;

&lt;p&gt;If the answer is "still plenty: architecture decisions, complex debugging, cross-team alignment, technical strategy, reviewing AI output critically" — you're probably in good shape. You've built the kind of irreplaceable judgment that AI, as of today, genuinely cannot replicate.&lt;/p&gt;

&lt;p&gt;If the answer is "I'm not sure" or "honestly, a lot of what I do could probably be generated" — that's important information. That's a signal worth acting on now, not later.&lt;/p&gt;

&lt;p&gt;Among Gen Z developers, 64% report worrying about being laid off, compared to 45% of their millennial counterparts, per Stack Overflow's Developer Survey. Those numbers aren't paranoia. They're pattern recognition. Gen Z engineers entered a market that looked like one thing and found something completely different when they arrived.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Honest Summary
&lt;/h2&gt;

&lt;p&gt;Will AI replace software engineers? No. The discipline of engineering — systems thinking, architecture, the judgment that comes from having built things that broke — is genuinely hard to replicate and AI is genuinely bad at it.&lt;/p&gt;

&lt;p&gt;But will AI shrink junior roles, compress the hiring pipeline, raise the floor of what's expected at every level, and leave a smaller total number of engineers employed than the 2022 peak? It already has. That's not a prediction. That's a 2026 fact.&lt;/p&gt;

&lt;p&gt;In 2025 alone, at least 58 million workers globally received some form of AI training or certification, reflecting the scale of workforce transition already underway. The people who are going to be fine are the ones treating that transition not as a professional option but as a professional requirement.&lt;/p&gt;

&lt;p&gt;AI is not optional anymore. Not because some blog post said so. Because the hiring data, the layoff data, the productivity data, and the capital allocation data all point in the same direction. The companies with the most money in the world made their decision. They made it years ago.&lt;/p&gt;

&lt;p&gt;The question is just whether you make yours, and when.&lt;/p&gt;

&lt;p&gt;Because the engineers who ignore this — who wait for clarity, who keep doing what they've been doing and hope the market swings back to them — are making a bet. A bet that one of the best-funded, fastest-moving technological transitions in history is going to stall out before it reaches their desk.&lt;/p&gt;

&lt;p&gt;I wouldn't take that bet.&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.amazonaws.com%2Fuploads%2Farticles%2Fun0bivnk6yoslhd46yae.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.amazonaws.com%2Fuploads%2Farticles%2Fun0bivnk6yoslhd46yae.png" alt="Depicting an image on What you can do now" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Can Do, Starting Now
&lt;/h2&gt;

&lt;p&gt;Not a lecture. Just what I'd do.&lt;/p&gt;

&lt;p&gt;Start using AI tools as a real collaborator, not as autocomplete. Use Claude Code, Cursor, Copilot — use multiple, because they have different strengths and critically different failure modes. Build things with them. Learn where they fail. That failure map is your professional edge, because knowing when the AI is wrong is worth far more than being able to generate code you can't evaluate.&lt;/p&gt;

&lt;p&gt;Build the skills AI provably can't replicate in 2026: distributed systems design, security architecture, ML infrastructure, technical leadership, the ability to translate business requirements into technical decisions that account for real operational constraints. These are deeply human skills right now.&lt;/p&gt;

&lt;p&gt;Write publicly about what you're building and learning. In a market where AI can produce anyone's code sample, your &lt;em&gt;thinking&lt;/em&gt; has to be the differentiator. Make it visible.&lt;/p&gt;

&lt;p&gt;And invest real time in the business side. Understand the domain you're building in. Talk to the users. Learn enough about the product and the economics to make real decisions — not just technical ones. That combination of technical depth plus business fluency is, right now, as hard to replace as anything in this industry.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;The friend I opened with — he's okay. After three rejections in a row, he spent three months rebuilding his workflow. AI for 60–70% of implementation. Critical review of everything it produced. He built a real sense of where it went wrong. Got back to final rounds. Got the job.&lt;/p&gt;

&lt;p&gt;But he lost months. He lost income. He went through the specific kind of humiliation that comes with being objectively skilled at something and still being passed over — not for someone better, but for someone who had simply adapted faster. The only reason was timing. He moved slower than the market moved.&lt;/p&gt;

&lt;p&gt;Don't be him. Move now.&lt;/p&gt;

&lt;p&gt;The question was never whether AI will replace software engineers. The question has always been whether &lt;em&gt;you&lt;/em&gt; will make yourself the kind of engineer that AI makes more powerful — or one that AI makes obsolete. That answer is entirely up to you.&lt;/p&gt;

&lt;p&gt;But you don't have unlimited time to decide.&lt;/p&gt;




&lt;h3&gt;
  
  
  References &amp;amp; Sources
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Additional data from: Stanford HAI 2026 AI Index · Stanford Digital Economy Lab · Stack Overflow Developer Survey 2024–2025 · Indeed Labour Market Data · Tech Layoff Tracker (May 2026) · Harvard Business Review (February 2026)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Find me across the web:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Salesforce Q4 FY2025 Earnings Call — Marc Benioff, CEO&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Joe Rogan Experience, January 2025 — Mark Zuckerberg, CEO of Meta&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Alphabet Q3 2024 Earnings Call; Google Cloud Next 2026 (April 22, 2026) — Sundar Pichai, CEO of Google&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;Microsoft Build 2025 — Satya Nadella, CEO of Microsoft&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;Microsoft/GitHub Copilot Productivity Study, 2025&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;World Economic Forum — Future of Jobs Report 2025 &amp;amp; Reskilling Revolution Initiative&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn7"&gt;
&lt;p&gt;NASSCOM AI Talent Report 2026; Indian Ministry of Labour and Employment&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn8"&gt;
&lt;p&gt;U.S. Bureau of Labor Statistics, Occupational Employment Data, 2025&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn9"&gt;
&lt;p&gt;Resume.org Survey of 1,000 U.S. Business Leaders, 2025&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn10"&gt;
&lt;p&gt;SignalFire Entry-Level Hiring Report, 2024&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn11"&gt;
&lt;p&gt;National Association of Colleges and Employers (NACE) — Job Outlook 2026&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>discuss</category>
      <category>git</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Java vs C# in Kubernetes: A Practical Guide to Docker Optimization in 2026</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Sun, 31 May 2026 09:58:22 +0000</pubDate>
      <link>https://dev.to/syedahmershah/java-vs-c-optimizing-docker-for-kubernetes-1kkc</link>
      <guid>https://dev.to/syedahmershah/java-vs-c-optimizing-docker-for-kubernetes-1kkc</guid>
      <description>&lt;p&gt;There's a question that keeps surfacing across engineering teams — sometimes in architecture reviews, sometimes buried in a Slack thread at 11 PM the night before a production incident — and it goes something like this: &lt;em&gt;we're containerizing everything for Kubernetes, we're choosing between Java and C#, and we want to get this right.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Both ecosystems have matured enormously in the container space. Both have answers to the problems that plagued them five years ago. But those answers are different, the tradeoffs are real, and the wrong defaults will silently cost you — in cloud bills, in startup latency, and in operational headaches that only show up when things go wrong at scale.&lt;/p&gt;

&lt;p&gt;This article doesn't take sides. What it does is go deep on what actually matters when you're building and deploying Java or C# services on Kubernetes: image sizes, startup behavior, JVM tuning, .NET Native AOT, garbage collection, memory limits, probe configuration, and the specific mistakes that bite teams over and over again.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Modern State of Java and C# in 2026
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Java
&lt;/h3&gt;

&lt;p&gt;Java 25 is the current LTS as of late 2025. The language and runtime have come a long way — virtual threads (Project Loom) are stable and production-ready, the JVM's container awareness has been solid for years, and GraalVM Native Image has matured into a legitimate production option for teams willing to work within its constraints.&lt;/p&gt;

&lt;p&gt;Spring Boot 3.x remains the dominant framework for backend Java, though Quarkus and Micronaut have carved out real niches precisely because they were designed with containers and fast startup times in mind from day one. For JDK distributions, Eclipse Temurin is the community standard, with Red Hat's OpenJDK and Azul Zulu as solid alternatives. All three have first-class Docker support.&lt;/p&gt;

&lt;p&gt;What changed in recent Java versions that actually matters for containers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;UseContainerSupport&lt;/code&gt;&lt;/strong&gt; is enabled by default, so the JVM reads cgroup memory and CPU limits correctly instead of sizing itself against the host machine — a problem that plagued early containerized JVM deployments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;MaxRAMPercentage&lt;/code&gt;&lt;/strong&gt; gives you a clean, portable way to configure heap without hardcoding megabyte values that break when you resize your pods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ZGC and Shenandoah&lt;/strong&gt; are both production-grade, low-pause garbage collectors that behave well in memory-constrained environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AppCDS&lt;/strong&gt; (Application Class Data Sharing) genuinely improves startup time for traditional JVM deployments without requiring a full recompilation model.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note on the examples below:&lt;/strong&gt; Dockerfiles in this article use the &lt;code&gt;21&lt;/code&gt; tag, which maps to a widely-available and stable Eclipse Temurin release. If you're starting fresh, substitute &lt;code&gt;25&lt;/code&gt; once your toolchain — especially GraalVM — has matching image support. Always check Docker Hub for available tags before pinning a version in production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  .NET
&lt;/h3&gt;

&lt;p&gt;.NET 10 is the current LTS as of November 2025. Microsoft has invested heavily in container-first deployment across several releases. Native AOT, still experimental in .NET 7, became a first-class feature in .NET 8 and has been progressively better supported in ASP.NET Core through .NET 9 and 10.&lt;/p&gt;

&lt;p&gt;The chiseled Ubuntu images Microsoft maintains are stripped-down, non-root-by-default base images that produce significantly smaller final containers than the traditional &lt;code&gt;aspnet&lt;/code&gt; base images. ReadyToRun compilation, trimming, and ahead-of-time compilation give .NET more optimization levers than it's ever had.&lt;/p&gt;

&lt;p&gt;ASP.NET Core Minimal APIs pair particularly well with Native AOT, since they sidestep the reflection-heavy patterns that AOT struggles with. If you're building new services and targeting native compilation, Minimal APIs are the right starting point — not as a preference, but because the AOT compatibility story is genuinely better there.&lt;/p&gt;




&lt;h2&gt;
  
  
  Docker Fundamentals That Actually Matter Here
&lt;/h2&gt;

&lt;p&gt;Before getting into language-specific details, a few fundamentals worth internalizing if you haven't already.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image size&lt;/strong&gt; affects pull time, storage cost, and attack surface. Smaller images pull faster during pod scheduling, cost less in registry storage, and give attackers fewer tools to work with after a container compromise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Startup time&lt;/strong&gt; matters enormously in Kubernetes because pods restart, scale out, and get rescheduled constantly. A 30-second JVM startup that seems acceptable in staging turns into a real problem when your autoscaler is trying to add capacity during a traffic spike.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory behavior&lt;/strong&gt; determines whether you're crashing pods under pressure or over-provisioning and wasting money. &lt;strong&gt;CPU behavior&lt;/strong&gt; determines whether you're hitting throttling under load.&lt;/p&gt;

&lt;p&gt;Both Java and C# have specific characteristics in each of these dimensions that differ from Go or Rust containers, which is why generic Docker optimization advice often misses the mark for these runtimes. A JVM service and a statically compiled Go binary are fundamentally different runtime models, and your container strategy needs to reflect that.&lt;/p&gt;

&lt;h2&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.amazonaws.com%2Fuploads%2Farticles%2Fbeyufkibe94meumvars2.png" alt="Multi-stage build diagram — build stage on the left, runtime stage on the right, with an arrow showing what gets copied and what gets dropped" width="800" height="336"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Java Container Optimization
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Multi-Stage Builds Are Non-Negotiable
&lt;/h3&gt;

&lt;p&gt;Shipping a full JDK in your production image is wasteful in almost every sense. A naive Java Dockerfile pulls in a 500+ MB JDK image along with your fat JAR, and the build toolchain has absolutely no business being in a production container.&lt;/p&gt;

&lt;p&gt;Here's a reasonable starting point for a Spring Boot service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: Build&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;eclipse-temurin:21-jdk-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;./mvnw clean package &lt;span class="nt"&gt;-DskipTests&lt;/span&gt;

&lt;span class="c"&gt;# Stage 2: Runtime only&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; eclipse-temurin:21-jre-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/target/*.jar app.jar&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-S&lt;/span&gt; appgroup &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser &lt;span class="nt"&gt;-S&lt;/span&gt; appuser &lt;span class="nt"&gt;-G&lt;/span&gt; appgroup
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; appuser&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["java", \&lt;/span&gt;
  "-XX:+UseContainerSupport", \
  "-XX:MaxRAMPercentage=75.0", \
  "-XX:+UseZGC", \
  "-jar", "app.jar"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Switching from a JDK to a JRE-only base image cuts roughly 200–300 MB from the final image. Alpine-based images shave off more, but they use musl libc instead of glibc — which occasionally surfaces compatibility issues with native libraries compiled against glibc. Worth testing before committing to Alpine in production, especially if you use dependencies with native components like certain database drivers or crypto libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Distroless Containers
&lt;/h3&gt;

&lt;p&gt;Google's Distroless images take this a step further. They contain only the Java runtime and your application — no shell, no package manager, no OS utilities that an attacker could misuse after a container compromise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: Build&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;eclipse-temurin:21-jdk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;./mvnw clean package &lt;span class="nt"&gt;-DskipTests&lt;/span&gt;

&lt;span class="c"&gt;# Stage 2: Distroless runtime&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; gcr.io/distroless/java21-debian12&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/target/*.jar app.jar&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["java", \&lt;/span&gt;
  "-XX:+UseContainerSupport", \
  "-XX:MaxRAMPercentage=75.0", \
  "-XX:+UseZGC", \
  "-jar", "app.jar"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Debugging distroless containers is harder — no shell means no &lt;code&gt;kubectl exec&lt;/code&gt; for ad-hoc inspection. You'll need &lt;code&gt;kubectl debug&lt;/code&gt; with an ephemeral sidecar, or rely entirely on your observability stack. That's a fair tradeoff for production security, but make sure your team understands and accepts that operational model before adopting it.&lt;/p&gt;

&lt;h3&gt;
  
  
  GraalVM Native Image
&lt;/h3&gt;

&lt;p&gt;This is the most significant shift available to Java teams, and it's worth understanding properly rather than just copy-pasting the Dockerfile.&lt;/p&gt;

&lt;p&gt;GraalVM Native Image compiles your application ahead-of-time into a standalone native binary — no JVM, no warmup. Startup times drop from seconds to milliseconds. Memory footprint drops dramatically because you're no longer carrying a JIT compiler, metaspace, or a full runtime in memory.&lt;/p&gt;

&lt;p&gt;Spring Boot 3.x has first-class support for Native Image through native Maven and Gradle plugins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: Native compile&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ghcr.io/graalvm/native-image:21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;./mvnw &lt;span class="nt"&gt;-Pnative&lt;/span&gt; native:compile &lt;span class="nt"&gt;-DskipTests&lt;/span&gt;

&lt;span class="c"&gt;# Stage 2: C runtime only — this is a native binary, not a JAR&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; gcr.io/distroless/cc-debian12&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/target/myservice .&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/app/myservice"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the runtime base image is &lt;code&gt;distroless/cc-debian12&lt;/code&gt; — not a Java base. Since the output is a native binary, you only need glibc and the C runtime, not a JVM. This keeps the final image genuinely small and free of Java metadata.&lt;/p&gt;

&lt;p&gt;The build takes longer — 5–15 minutes for a complex service is normal — and there are real constraints around reflection, dynamic class loading, and runtime proxies that require explicit configuration hints in &lt;code&gt;reflect-config.json&lt;/code&gt; and &lt;code&gt;resource-config.json&lt;/code&gt;. For frameworks that lean heavily on reflection, writing those hints is a genuine time investment, not an afternoon task.&lt;/p&gt;

&lt;p&gt;The reward is a service that starts in 50–100ms, uses a fraction of the heap, and deploys as a compact binary. For event-driven microservices, serverless-style patterns, or anything that scales to zero, Native Image is the right choice. For long-running, compute-intensive services where JIT's aggressive runtime optimization pays off at peak throughput, the traditional JVM still has the edge.&lt;/p&gt;

&lt;h3&gt;
  
  
  JVM Tuning for Containers
&lt;/h3&gt;

&lt;p&gt;A handful of flags that matter specifically in Kubernetes environments:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;-XX:+UseContainerSupport&lt;/code&gt;&lt;/strong&gt; — Enabled by default since JDK 10. Reads cgroup limits correctly. Never disable it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;-XX:MaxRAMPercentage=75.0&lt;/code&gt;&lt;/strong&gt; — Sets heap to 75% of available container memory. The remaining 25% covers metaspace, code cache, thread stacks, and native allocations. Setting this to 100% will trigger OOMKills even though the heap "fits" — there's always non-heap consumption to account for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;-XX:+UseZGC&lt;/code&gt;&lt;/strong&gt; — Delivers consistent low-pause garbage collection, well-suited for latency-sensitive services. G1GC is the default and solid for most workloads, but ZGC's pause times are more predictable under memory pressure. Shenandoah is a reasonable alternative with similar design goals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;-XX:+TieredCompilation -XX:TieredStopAtLevel=1&lt;/code&gt;&lt;/strong&gt; — Can improve startup time at the cost of peak throughput. Useful if you're not on Native Image but need faster pod readiness for frequent scaling events.&lt;/p&gt;

&lt;p&gt;For services that restart frequently or scale aggressively, AppCDS is worth the setup effort. It serializes class metadata to a shared archive that gets memory-mapped on startup, reducing JVM initialization time by several seconds for large applications:&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;# Step 1: Generate the class list&lt;/span&gt;
java &lt;span class="nt"&gt;-XX&lt;/span&gt;:DumpLoadedClassList&lt;span class="o"&gt;=&lt;/span&gt;app.classlist &lt;span class="nt"&gt;-jar&lt;/span&gt; app.jar

&lt;span class="c"&gt;# Step 2: Create the shared archive&lt;/span&gt;
java &lt;span class="nt"&gt;-Xshare&lt;/span&gt;:dump &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-XX&lt;/span&gt;:SharedClassListFile&lt;span class="o"&gt;=&lt;/span&gt;app.classlist &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-XX&lt;/span&gt;:SharedArchiveFile&lt;span class="o"&gt;=&lt;/span&gt;app.jsa &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-jar&lt;/span&gt; app.jar

&lt;span class="c"&gt;# Step 3: Use the archive at runtime&lt;/span&gt;
java &lt;span class="nt"&gt;-Xshare&lt;/span&gt;:on &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-XX&lt;/span&gt;:SharedArchiveFile&lt;span class="o"&gt;=&lt;/span&gt;app.jsa &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-XX&lt;/span&gt;:MaxRAMPercentage&lt;span class="o"&gt;=&lt;/span&gt;75.0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-XX&lt;/span&gt;:+UseZGC &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-jar&lt;/span&gt; app.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&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.amazonaws.com%2Fuploads%2Farticles%2Fw96jhdf9rg6wkn0watp0.png" alt="JVM memory model diagram — showing heap, metaspace, code cache, thread stacks, and the cgroup memory boundary as a container wall" width="800" height="336"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  C# / .NET Container Optimization
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Multi-Stage Builds for .NET
&lt;/h3&gt;

&lt;p&gt;Same principle, same payoff. The .NET SDK image runs around 800 MB to 1 GB. Your production container needs only the ASP.NET Core runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: Build and publish&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/sdk:10.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet restore &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    dotnet publish &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;-o&lt;/span&gt; /app/publish

&lt;span class="c"&gt;# Stage 2: Chiseled runtime&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/publish .&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; app&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["dotnet", "MyApi.dll"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;noble-chiseled&lt;/code&gt; tag refers to Microsoft's chiseled Ubuntu images — stripped-down base images with minimal attack surface, non-root by default, and significantly smaller than the standard &lt;code&gt;aspnet&lt;/code&gt; images. Switching to chiseled is a one-line Dockerfile change that cuts the final image by 30–40% with zero code changes. If there's one thing to do before anything else on the .NET side, this is it.&lt;/p&gt;

&lt;h3&gt;
  
  
  .NET Native AOT
&lt;/h3&gt;

&lt;p&gt;Native AOT in .NET compiles your application into a standalone native binary at publish time — the .NET equivalent of GraalVM Native Image, with similar tradeoffs in both directions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: AOT publish&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/sdk:10.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet publish &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;-r&lt;/span&gt; linux-x64 &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--self-contained&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;-p&lt;/span&gt;:PublishAot&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;-o&lt;/span&gt; /app/publish

&lt;span class="c"&gt;# Stage 2: C runtime only — no .NET runtime layer needed&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/publish .&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; app&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/app/MyApi"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Native AOT, you're on &lt;code&gt;runtime-deps&lt;/code&gt; rather than &lt;code&gt;aspnet&lt;/code&gt; — just the native C runtime, no .NET runtime layer at all. The final image can get surprisingly small, sometimes under 60 MB for a well-trimmed Minimal API service.&lt;/p&gt;

&lt;p&gt;Constraints to know before committing: reflection must be declared via &lt;code&gt;[DynamicallyAccessedMembers]&lt;/code&gt; attributes or &lt;code&gt;rd.xml&lt;/code&gt; files, serialization works well with &lt;code&gt;System.Text.Json&lt;/code&gt;'s source generation mode, and Entity Framework Core has limited Native AOT support depending on the database provider and version. Check your specific dependencies before going down this path for data-heavy services.&lt;/p&gt;

&lt;h3&gt;
  
  
  ReadyToRun and Trimming
&lt;/h3&gt;

&lt;p&gt;If full Native AOT feels like too much overhead for a given service, ReadyToRun provides ahead-of-time compilation of IL to native code — faster startup without the full AOT constraints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet publish &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;-r&lt;/span&gt; linux-x64 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--self-contained&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-p&lt;/span&gt;:PublishReadyToRun&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-p&lt;/span&gt;:PublishTrimmed&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trimming removes unreachable IL code from the published output, meaningfully reducing image size. It does require careful testing — it can silently remove code paths that appear dead to the linker but are invoked via reflection at runtime. Run your full integration and end-to-end test suite after enabling it. Unit tests alone are unlikely to catch trimming-caused failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory Configuration for .NET Containers
&lt;/h3&gt;

&lt;p&gt;.NET manages its heap differently from the JVM. Key environment variables for containerized .NET services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;DOTNET_GCHeapHardLimit&lt;/code&gt;&lt;/strong&gt; — Sets a hard memory ceiling for the GC in bytes. Useful for strict per-pod memory isolation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;DOTNET_GCConserveMemory&lt;/code&gt;&lt;/strong&gt; — A value from 0 to 9 that trades GC aggressiveness for memory conservation. Values of 5–7 are useful under memory pressure; higher values reduce footprint at the cost of more frequent collections. Start at 0 and tune up only if you're seeing memory strain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;DOTNET_SYSTEM_GC_SERVER&lt;/code&gt;&lt;/strong&gt; — Defaults to &lt;code&gt;true&lt;/code&gt; in containers since .NET 6. Server GC is appropriate for backend services on multi-core hosts and rarely needs to be overridden.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Kubernetes-Specific Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Resource Requests and Limits
&lt;/h3&gt;

&lt;p&gt;This is where Java teams most frequently get burned. Without resource requests and limits, the Kubernetes scheduler has no useful information, and your pods will get evicted under memory pressure without warning — often at the worst possible moment.&lt;/p&gt;

&lt;p&gt;For a traditional JVM service:&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;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;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;500m"&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;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1Gi"&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2000m"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the memory limit conservatively above your expected heap plus overhead. Setting memory request equal to limit (Guaranteed QoS class) prevents OOM eviction under cluster memory pressure — worth doing for latency-critical services. For native compilation services, you can set much tighter limits — often 64–128 Mi memory, 100–250m CPU — and that's where the real resource efficiency gains show up at scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Startup Probes, Readiness, and Liveness
&lt;/h3&gt;

&lt;p&gt;This trio is critical and commonly misconfigured, and getting it wrong causes cascading problems that are genuinely painful to debug.&lt;/p&gt;

&lt;p&gt;The startup probe exists specifically for slow-starting applications. It gives the container time to initialize before the liveness probe kicks in and starts restarting it for appearing unhealthy:&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;startupProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/actuator/health/readiness&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;failureThreshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
  &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

&lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/actuator/health/readiness&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;failureThreshold&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;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/actuator/health/liveness&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
  &lt;span class="na"&gt;failureThreshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spring Boot Actuator exposes &lt;code&gt;/actuator/health/readiness&lt;/code&gt; and &lt;code&gt;/actuator/health/liveness&lt;/code&gt; out of the box when you add &lt;code&gt;management.health.probes.enabled=true&lt;/code&gt; to your application properties. ASP.NET Core has built-in health check endpoints via &lt;code&gt;app.MapHealthChecks("/healthz")&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never route the liveness probe to an endpoint that checks downstream dependencies.&lt;/strong&gt; If your database is slow, that should affect readiness — stop sending traffic to this pod — not liveness, which triggers a restart. Misconfiguring this is one of the most common causes of cascading pod restart storms during dependency degradation: slow database causes pod restarts, pod restarts add more connection pressure to the database, which makes it slower, which causes more restarts.&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.amazonaws.com%2Fuploads%2Farticles%2Fjvnkgom8xkh4j6t72caj.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.amazonaws.com%2Fuploads%2Farticles%2Fjvnkgom8xkh4j6t72caj.png" alt="Kubernetes probe lifecycle diagram — a horizontal timeline showing startupProbe window → readinessProbe active → livenessProbe active, with what happens at each phase" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Autoscaling
&lt;/h3&gt;

&lt;p&gt;CPU-based HPA is the baseline, but for JVM services it can be misleading during JIT warmup. JVM pods spike CPU on startup in ways that don't reflect steady-state load — your autoscaler sees those spikes, adds more pods, which also spike CPU on start, and suddenly you have more pods than you actually need.&lt;/p&gt;

&lt;p&gt;For JVM services, memory-based or request-rate-based autoscaling gives more meaningful signals. KEDA (Kubernetes Event-driven Autoscaling) is worth evaluating for queue-depth or RPS-based scaling in production workloads:&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling/v2&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;HorizontalPodAutoscaler&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;java-service-hpa&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;scaleTargetRef&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;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;java-service&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
  &lt;span class="na"&gt;metrics&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;Resource&lt;/span&gt;
    &lt;span class="na"&gt;resource&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;memory&lt;/span&gt;
      &lt;span class="na"&gt;target&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;Utilization&lt;/span&gt;
        &lt;span class="na"&gt;averageUtilization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;70&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a complete Kubernetes Deployment manifest for a Java service, putting all of the above together:&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;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;java-service&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;java-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;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;java-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;java-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;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;runAsNonRoot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
        &lt;span class="na"&gt;runAsGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
        &lt;span class="na"&gt;seccompProfile&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;RuntimeDefault&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;java-service&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;myregistry/java-service:1.0.0&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&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;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;500m"&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;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1Gi"&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2000m"&lt;/span&gt;
        &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
          &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;drop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ALL&lt;/span&gt;
        &lt;span class="na"&gt;env&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;JAVA_TOOL_OPTIONS&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-XX:MaxRAMPercentage=75.0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-XX:+UseZGC"&lt;/span&gt;
        &lt;span class="na"&gt;startupProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/actuator/health/readiness&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="na"&gt;failureThreshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
          &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
        &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/actuator/health/readiness&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
          &lt;span class="na"&gt;failureThreshold&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;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/actuator/health/liveness&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
          &lt;span class="na"&gt;failureThreshold&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;lifecycle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;preStop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;exec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sh"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sleep&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;5"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;ter9yMnTm4NSzvG9rrwjM2ec8xZgh1cafXH8&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Java vs C# in Kubernetes: The Real Comparison
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Startup Speed
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7kzxeukgamkkejeu1j39.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.amazonaws.com%2Fuploads%2Farticles%2F7kzxeukgamkkejeu1j39.png" alt="Startup time comparison chart — horizontal bar chart with five bars: Traditional Spring Boot, Quarkus/Micronaut, GraalVM Native Image, ASP.NET Core JIT, .NET Native AOT" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Traditional Spring Boot commonly hits 10–15 seconds on cold start. Quarkus and Micronaut are faster by design — often 1–4 seconds — because they push more work to build time rather than runtime. GraalVM Native Image brings this down to 50–200ms, competitive with native Go and Rust binaries.&lt;/p&gt;

&lt;p&gt;On the .NET side, a typical ASP.NET Core service starts in 1–5 seconds on standard JIT. .NET Native AOT reaches 20–100ms — comparable to GraalVM Native Image.&lt;/p&gt;

&lt;p&gt;For standard Kubernetes deployments running 3–5 replicas with gradual scaling, a 10-second JVM startup is usually acceptable. For scale-to-zero patterns, event-driven architectures with bursty traffic, or rapid horizontal scaling, startup time becomes a real bottleneck and native compilation moves from a nice-to-have to essential.&lt;/p&gt;

&lt;p&gt;The more interesting comparison is between Quarkus and standard .NET JIT — they land in similar territory. If you're not using native compilation, .NET starts faster than traditional Spring Boot, but the gap largely disappears once you bring Quarkus or Micronaut into the equation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory Footprint
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfqupbm73gqejzex899f.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.amazonaws.com%2Fuploads%2Farticles%2Fyfqupbm73gqejzex899f.png" alt="Memory footprint comparison chart — bar chart with five runtime categories, same order as the startup chart" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A traditional Spring Boot service sits at roughly 300–600 MB under load once you account for everything the JVM carries — metaspace, JIT code cache, thread stacks, native memory allocations. The heap is only part of that picture.&lt;/p&gt;

&lt;p&gt;GraalVM Native Image drops this to 30–100 MB for the same service. The absence of the JVM runtime, JIT compiler, and metaspace is a dramatic reduction.&lt;/p&gt;

&lt;p&gt;A typical ASP.NET Core service lands at 80–200 MB. The .NET runtime is lighter than the JVM baseline without any special configuration, which is why .NET has historically had lower memory consumption than equivalent Spring Boot services out of the box.&lt;/p&gt;

&lt;p&gt;.NET Native AOT brings this down further to 20–80 MB.&lt;/p&gt;

&lt;p&gt;At scale — 50 pods of a microservice — the difference between a 400 MB JVM pod and an 80 MB native pod is 16 GB of cluster memory across a single service. That's real money on managed Kubernetes, and it compounds across every service in a large microservices architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Developer Experience and Build Complexity
&lt;/h3&gt;

&lt;p&gt;Standard JVM builds with Maven or Gradle are fast, well-understood, and easy to hire for. The CI setup is straightforward, the Dockerfile is simple, and most engineers on a Java team have seen this before. That's a real advantage that's easy to underestimate when weighing ecosystem choices.&lt;/p&gt;

&lt;p&gt;GraalVM Native Image builds are slower — 5–15 minutes for a complex service — and require dependency compatibility verification before you get a clean build. When &lt;code&gt;native:compile&lt;/code&gt; fails due to a reflection issue, the error messages can be cryptic. The Spring Boot native hints ecosystem has improved significantly, but it's still a meaningful investment for a non-trivial service.&lt;/p&gt;

&lt;p&gt;Standard .NET builds are fast and ergonomic. &lt;code&gt;dotnet publish&lt;/code&gt; is polished and the tooling tends to have a shorter learning curve than Maven or Gradle for engineers coming from other backgrounds.&lt;/p&gt;

&lt;p&gt;.NET Native AOT has similar build-time costs and constraint management overhead to GraalVM. The AOT analyzer and &lt;code&gt;ILLink&lt;/code&gt; warnings have improved substantially in recent .NET versions, making issues easier to diagnose — though "easier to diagnose" is relative when you're hunting for a trimming-caused regression.&lt;/p&gt;

&lt;p&gt;For teams without deep container optimization experience, .NET's standard setup tends to reach a reasonable baseline faster. For teams willing to invest the setup effort, both ecosystems' native compilation options produce broadly comparable results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ecosystem and Tooling
&lt;/h3&gt;

&lt;p&gt;Java's ecosystem is deeper in specific domains: financial services (Spring Batch, Apache Camel), data engineering (Kafka Streams, Flink, Spark), and enterprise integration. The Kubernetes operator ecosystem has extensive Java tooling, and most major cloud provider SDKs have strong Java support.&lt;/p&gt;

&lt;p&gt;.NET is the natural choice if you're Microsoft-stack heavy, Azure-native, or have significant existing C# codebase investments. The Azure SDK for .NET is excellent. If your team is building on SQL Server with EF Core and deploying to AKS, .NET is the path of least resistance by a wide margin.&lt;/p&gt;

&lt;p&gt;Neither ecosystem is a wrong choice for general microservice backend work in 2026. Let your integration requirements and existing team expertise drive the decision rather than synthetic benchmark numbers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Image Size Optimization
&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.amazonaws.com%2Fuploads%2Farticles%2Fhz2kbtlfprxsi8izk3bu.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.amazonaws.com%2Fuploads%2Farticles%2Fhz2kbtlfprxsi8izk3bu.png" alt="Image size progression — two side-by-side waterfall/funnel charts showing Java and .NET from worst to best configuration" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Java: Worst to Best
&lt;/h3&gt;

&lt;p&gt;Starting from a naive full JDK with fat JAR and no multi-stage build, you're looking at roughly 600 MB. Moving to a multi-stage build with a JRE-only base gets you to 250–300 MB. Alpine-based JRE images bring this down further to 150–200 MB, and Distroless images land at around 180–220 MB depending on the runtime version.&lt;/p&gt;

&lt;p&gt;From there, JLink is an underused option worth knowing about. It lets you build a custom JRE containing only the Java modules your application actually uses:&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;# Identify exactly which modules your JAR needs&lt;/span&gt;
jdeps &lt;span class="nt"&gt;--ignore-missing-deps&lt;/span&gt; &lt;span class="nt"&gt;--print-module-deps&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--class-path&lt;/span&gt; &lt;span class="s2"&gt;"BOOT-INF/lib/*"&lt;/span&gt; app.jar

&lt;span class="c"&gt;# Build a minimal JRE with only those modules&lt;/span&gt;
jlink &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--add-modules&lt;/span&gt; java.base,java.logging,java.sql,java.naming &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--strip-debug&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--no-man-pages&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--no-header-files&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--compress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; /custom-jre
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A JLink custom runtime combined with Distroless gets you to roughly 80–120 MB — meaningful size reduction without any Native Image constraints. GraalVM Native Image with Distroless represents the floor: 30–80 MB for a typical service.&lt;/p&gt;

&lt;h3&gt;
  
  
  .NET: Worst to Best
&lt;/h3&gt;

&lt;p&gt;The naive approach — SDK image with no multi-stage build — produces a container around 800 MB. A standard &lt;code&gt;aspnet&lt;/code&gt; multi-stage build gets you to 200–250 MB. Switching to chiseled images brings that to 100–140 MB, and adding trimming with self-contained deployment gets to 60–100 MB. Native AOT with &lt;code&gt;runtime-deps&lt;/code&gt; chiseled is the floor: 30–70 MB.&lt;/p&gt;

&lt;p&gt;The chiseled images are the easiest win that many teams haven't taken yet. Switching the final stage from &lt;code&gt;mcr.microsoft.com/dotnet/aspnet:10.0&lt;/code&gt; to &lt;code&gt;mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled&lt;/code&gt; is literally changing one word in your Dockerfile. Do that before anything else.&lt;/p&gt;




&lt;h2&gt;
  
  
  Monitoring and Observability
&lt;/h2&gt;

&lt;p&gt;Both ecosystems have solid OpenTelemetry support. For Java, the OpenTelemetry Java agent provides automatic instrumentation without code changes — attach it at runtime and your traces, metrics, and logs flow to the configured exporter without touching application code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; otel-javaagent.jar /otel-javaagent.jar&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; JAVA_TOOL_OPTIONS="-javaagent:/otel-javaagent.jar"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For .NET, the &lt;code&gt;OpenTelemetry.Extensions.Hosting&lt;/code&gt; package integrates cleanly with ASP.NET Core's &lt;code&gt;IHostBuilder&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenTelemetry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithTracing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tracing&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tracing&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAspNetCoreInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddHttpClientInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOtlpExporter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAspNetCoreInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRuntimeInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPrometheusExporter&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Micrometer (Java) and ASP.NET Core's built-in metrics APIs both produce Prometheus-compatible metrics. Standard Grafana dashboards cover JVM heap usage, GC pause times, thread pool utilization, HTTP request rates, and error rates out of the box.&lt;/p&gt;

&lt;p&gt;One important caveat for native compilation: observability tooling that relies on JVM internals or CLR profiling APIs won't work with GraalVM Native Image or .NET Native AOT. The OpenTelemetry SDK-based approach works correctly for both compilation targets, which is a strong reason to adopt SDK-based instrumentation over agent-based approaches if you're considering native compilation. Plan your observability strategy before committing to native — not after.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Non-Root Containers
&lt;/h3&gt;

&lt;p&gt;Every Dockerfile in this article explicitly drops to a non-root user. This isn't optional hygiene — it's the baseline. A surprising number of production Kubernetes deployments still run as root simply because the base image default was never overridden and nobody caught it in review.&lt;/p&gt;

&lt;p&gt;For Java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-S&lt;/span&gt; appgroup &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser &lt;span class="nt"&gt;-S&lt;/span&gt; appuser &lt;span class="nt"&gt;-G&lt;/span&gt; appgroup
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; appuser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For .NET, the chiseled images come with a non-root &lt;code&gt;app&lt;/code&gt; user by default. &lt;code&gt;USER app&lt;/code&gt; activates it.&lt;/p&gt;

&lt;p&gt;Enforce this at the cluster level with a pod security context too:&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;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;runAsNonRoot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
  &lt;span class="na"&gt;runAsGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
  &lt;span class="na"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;drop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ALL&lt;/span&gt;
  &lt;span class="na"&gt;seccompProfile&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;RuntimeDefault&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Vulnerability Scanning
&lt;/h3&gt;

&lt;p&gt;Include image scanning in your CI pipeline. Trivy is the standard open-source tool for this and integrates with GitHub Actions, GitLab CI, and most other platforms. The value of Distroless and chiseled images isn't purely about size — fewer OS packages means fewer CVEs to track and patch. A Distroless GraalVM native binary container and a full JDK Alpine image produce a meaningfully different CVE list when scanned. That difference grows louder every time there's a glibc or OpenSSL vulnerability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secrets Management
&lt;/h3&gt;

&lt;p&gt;Don't bake secrets into images — not even as build arguments. In Kubernetes, use &lt;code&gt;envFrom&lt;/code&gt; with native Secrets for low-sensitivity configuration, or the External Secrets Operator with Vault, AWS Secrets Manager, or Azure Key Vault for sensitive credentials. Both Spring Boot and ASP.NET Core read configuration cleanly from environment variables and mounted secret files without any special library dependencies.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes Teams Make
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Java-Specific Mistakes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Setting &lt;code&gt;-Xmx&lt;/code&gt; to a fixed value without accounting for non-heap memory.&lt;/strong&gt; The JVM consumes memory beyond the heap — metaspace, code cache, direct buffers, thread stacks. Setting &lt;code&gt;-Xmx&lt;/code&gt; to the container's full memory limit will trigger OOMKills even though the heap "fits." Use &lt;code&gt;-XX:MaxRAMPercentage=75.0&lt;/code&gt; instead and let the JVM calculate from available container memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not configuring a startup probe for JVM services.&lt;/strong&gt; Without a startup probe, the liveness probe runs immediately and restarts the pod during normal JVM warmup. This is one of the most common causes of pod restart loops on deploy that teams debug for hours before realizing what's happening.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shipping the build stage image as the final image.&lt;/strong&gt; An &lt;code&gt;eclipse-temurin:21-jdk&lt;/code&gt; final image includes compilers, header files, and build tools that have no purpose in a production container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assuming GraalVM Native Image just works on the first attempt.&lt;/strong&gt; A Spring Boot application with several dependencies will require reflection hints, proxy configurations, and resource includes. Budget real time for this — it isn't a one-afternoon project for a complex service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignoring JIT warmup in CPU-based HPA.&lt;/strong&gt; JVM services spike CPU on startup. If your HPA is watching CPU utilization, it will scale up pods during normal restarts, which also spike CPU, causing more scale-up. Use memory-based or request-rate-based HPA for JVM services.&lt;/p&gt;

&lt;h3&gt;
  
  
  .NET-Specific Mistakes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Using &lt;code&gt;mcr.microsoft.com/dotnet/sdk:10.0&lt;/code&gt; as the final image base.&lt;/strong&gt; The SDK is for building. The &lt;code&gt;aspnet&lt;/code&gt; or &lt;code&gt;runtime-deps&lt;/code&gt; image is for running. This produces containers approaching 1 GB that are slow to pull and expose unnecessary attack surface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enabling &lt;code&gt;PublishTrimmed=true&lt;/code&gt; without testing.&lt;/strong&gt; Trimming can silently remove functionality if reflection patterns aren't annotated with &lt;code&gt;[DynamicallyAccessedMembers]&lt;/code&gt;. Run your full integration and end-to-end test suite after enabling trimming — unit tests alone are unlikely to catch failures caused by it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Publishing for the wrong architecture.&lt;/strong&gt; Building on an ARM Mac and publishing for &lt;code&gt;linux-arm64&lt;/code&gt;, then deploying to an x64 node pool, produces a container that crashes immediately on start. Be explicit about &lt;code&gt;-r linux-x64&lt;/code&gt; or use multi-platform builds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not setting &lt;code&gt;ASPNETCORE_ENVIRONMENT=Production&lt;/code&gt;.&lt;/strong&gt; Without it, development-mode behaviors may activate — including detailed error pages that expose stack traces to anyone who can reach the service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kubernetes Deployment Mistakes (Both Ecosystems)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No &lt;code&gt;preStop&lt;/code&gt; hook and an insufficient &lt;code&gt;ter9yMnTm4NSzvG9rrwjM2ec8xZgh1cafXH8&lt;/code&gt;.&lt;/strong&gt; When Kubernetes terminates a pod, it sends SIGTERM and simultaneously removes the pod from the load balancer. Without a &lt;code&gt;preStop&lt;/code&gt; sleep of a few seconds, in-flight requests get dropped. Add &lt;code&gt;preStop: exec: command: ["sh", "-c", "sleep 5"]&lt;/code&gt; and ensure &lt;code&gt;ter9yMnTm4NSzvG9rrwjM2ec8xZgh1cafXH8&lt;/code&gt; is long enough for your service to drain — 60 seconds is a reasonable starting point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Readiness probes that check external dependencies.&lt;/strong&gt; If your readiness probe calls the database, a slow database will knock pods out of the load balancer rotation, increasing database pressure further. The readiness probe should answer one question: is &lt;em&gt;this specific pod&lt;/em&gt; ready to handle requests right now? Downstream dependency health belongs in the application layer, not in Kubernetes probes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No &lt;code&gt;PodDisruptionBudget&lt;/code&gt;.&lt;/strong&gt; Without a PDB, Kubernetes can evict all pods of a deployment simultaneously during node maintenance, causing complete service downtime. Set &lt;code&gt;minAvailable: 1&lt;/code&gt; or &lt;code&gt;maxUnavailable: 1&lt;/code&gt; for any service with availability requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Recommendations
&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.amazonaws.com%2Fuploads%2Farticles%2F19w6z42w84mqe5qj0ca3.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.amazonaws.com%2Fuploads%2Farticles%2F19w6z42w84mqe5qj0ca3.png" alt="" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  When Java Makes More Sense
&lt;/h3&gt;

&lt;p&gt;You're in a Java-heavy organization with existing Spring Boot or Quarkus expertise that goes beyond surface familiarity. You're building data-intensive or integration-heavy services where the JVM ecosystem is a genuine advantage — Kafka Streams, JPA, Apache Camel, Flink. Your services are long-running with stable, predictable load patterns where JIT compilation pays off in peak throughput. You need deep integration with Java-native cloud tooling.&lt;/p&gt;

&lt;h3&gt;
  
  
  When .NET Makes More Sense
&lt;/h3&gt;

&lt;p&gt;You're Azure-native or Microsoft-stack heavy. Your team's core expertise is C# and you want to leverage that fluency in framework APIs and ecosystem libraries. You need fast cold starts on standard JIT builds without investing in Native Image's build constraints. You're migrating Windows-origin backend code to Linux containers — the migration path is significantly smoother staying in .NET.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Native Compilation Makes Sense for Either
&lt;/h3&gt;

&lt;p&gt;Your architecture has scale-to-zero or rapid burst scaling requirements where cold start latency directly affects user experience or SLOs. Memory costs at scale are significant and you've done the math on how much native compilation saves at your pod count. Your services are stateless, structurally simple, and don't depend on reflection-heavy framework features. You have CI infrastructure that can absorb 10–15-minute native builds without blocking your team.&lt;/p&gt;

&lt;h3&gt;
  
  
  What to Prioritize, In Order
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Multi-stage builds.&lt;/strong&gt; Highest ROI, lowest effort. Every Java and .NET service should use multi-stage builds before any other optimization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Resource requests and limits with correct probe configuration.&lt;/strong&gt; An unstable deployment costs more than an unoptimized one. Get this right before worrying about image size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Non-root containers and security context.&lt;/strong&gt; Baseline professionalism, and required by most organization security policies and compliance frameworks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Chiseled images (.NET) or JRE images (Java).&lt;/strong&gt; Easy size wins with minimal effort and zero code changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Memory tuning.&lt;/strong&gt; Once you have observability and real load data, tune based on actual heap behavior — not guesses or defaults.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Native compilation.&lt;/strong&gt; Evaluate after you have real production metrics showing that startup time or memory footprint is actually a problem at your scale. Don't optimize prematurely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Java and C# are both credible, production-ready choices for Kubernetes-native backend development in 2026. The gap that existed five years ago — where Java containers were notoriously heavy and slow to start — has been substantially closed through GraalVM Native Image, Spring Boot's native AOT support, and better JVM container awareness. The JVM is no longer the obvious wrong choice for cloud-native work.&lt;/p&gt;

&lt;p&gt;.NET's traditional edge in startup time and memory footprint on standard JIT builds remains, but the difference is less dramatic than it once was. Where .NET Native AOT and GraalVM Native Image meet, the numbers are comparable.&lt;/p&gt;

&lt;p&gt;The practical decision factors are ecosystem fit, team expertise, existing infrastructure, and specific service requirements — not abstract language benchmarks. A well-optimized Java service with proper multi-stage builds, ZGC configuration, and sensible memory settings will outperform a poorly configured .NET service, and the reverse is equally true.&lt;/p&gt;

&lt;p&gt;What separates well-run container deployments from poorly-run ones isn't which language you chose. It's whether you're using multi-stage builds, whether your resource requests and limits reflect measured reality, whether your probes are configured correctly, and whether you have observability to catch problems before they become incidents. Get those fundamentals right first. Then optimize.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Find me across the web:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
      <category>java</category>
      <category>csharp</category>
      <category>docker</category>
    </item>
    <item>
      <title>I Coded My Portfolio From Scratch. No Templates.</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Tue, 26 May 2026 18:22:40 +0000</pubDate>
      <link>https://dev.to/syedahmershah/i-coded-my-portfolio-from-scratch-no-templates-5ed7</link>
      <guid>https://dev.to/syedahmershah/i-coded-my-portfolio-from-scratch-no-templates-5ed7</guid>
      <description>&lt;p&gt;There is a very specific kind of regret that hits when you deploy someone else's template, change the name and the profile picture, push it to GitHub, and then look at the result and think — yeah. That's me. That's my work.&lt;/p&gt;

&lt;p&gt;It's not. It never was.&lt;/p&gt;

&lt;p&gt;I made that mistake once. Grabbed something off a free portfolio site, tweaked the colors a bit, added my name in the hero section. It looked clean. It looked professional even. But whenever someone asked me about it I'd skip over the details because deep down I knew I hadn't built any of it. I had dressed up someone else's house and called it home.&lt;/p&gt;

&lt;p&gt;So when I finally decided to sit down and build &lt;a href="https://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt; properly, the first rule I set for myself was simple — no template. Not even as a reference. Start from index.html and figure the rest out.&lt;/p&gt;

&lt;p&gt;What followed was months of fighting with CSS, arguing with Three.js, debugging scroll behavior at 1 AM, and slowly building something that I can actually explain line by line. This is that story.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Templates Are a Trap (For Beginners Especially)
&lt;/h2&gt;

&lt;p&gt;Before I get into the build, I want to actually say something here because I see this conversation come up constantly in developer communities. People ask — should I use a template for my portfolio? And the nice answer is: it depends.&lt;/p&gt;

&lt;p&gt;The honest answer is: if you're learning, a template will stunt you.&lt;/p&gt;

&lt;p&gt;Using a template means you skip the decisions. You skip figuring out why a section is structured the way it is, why a certain animation works the way it does, why the developer chose to reach for a library instead of writing something custom. You inherit a finished product and you don't get any of the understanding that came from building it.&lt;/p&gt;

&lt;p&gt;Now if you're a senior developer trying to ship a portfolio in a weekend because you're job hunting — sure. Template makes sense. Time is money.&lt;/p&gt;

&lt;p&gt;But if you're a student, if you're early in your career, if you're trying to prove to yourself and to the people hiring you that you can build things — then building your own portfolio is genuinely one of the best projects you can do. Not because the portfolio itself is impressive. Because the process of building it forces you to answer real questions.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack and Why It Looks the Way It Does
&lt;/h2&gt;

&lt;p&gt;My stack for this project is: HTML5, custom CSS (this is the majority of the codebase, not Bootstrap), Bootstrap 5 for the grid layer only, vanilla JavaScript, a little bit of jQuery (honestly way less than I planned), Three.js, TurnJS, TiltJS, Lenis.js, and AJAX for some of the dynamic loading. Contact form runs through Formspree.&lt;/p&gt;

&lt;p&gt;If you look at the repo's language breakdown — it's 50.7% JavaScript, 29.3% CSS, 20% HTML. That CSS number felt right when I saw it. A lot of the complexity in this site lives in the stylesheets.&lt;/p&gt;

&lt;p&gt;I want to explain why the stack ended up looking like this because I made some deliberate choices and some accidental ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bootstrap vs Custom CSS — this one matters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The instinct a lot of beginners have is to let Bootstrap do everything. You end up with like 50 utility classes on every div and very little actual understanding of what the layout is doing. I made the decision early on to use Bootstrap only for the grid system and for a few responsive breakpoints. Everything else — spacing, typography, animations, color, positioning — is custom CSS using variables.&lt;/p&gt;

&lt;p&gt;This was slower. It was also much better for me as a developer. When something broke I had to understand &lt;em&gt;why&lt;/em&gt; it broke instead of just switching utility classes until it looked right.&lt;/p&gt;

&lt;p&gt;The result is a CSS file that is actually kind of long and in some places probably not perfectly organized. That's real. I'm not going to pretend the codebase is immaculate. There are sections where I know I could refactor things, places where I wrote a specific rule to fix a very specific layout problem and then never cleaned it up properly. The site works and it looks good but the code behind it has the marks of something that was built iteratively over time, not planned from the start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript — mostly vanilla, jQuery at the edges&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I planned to use jQuery more. Ended up using it way less. Vanilla JS handles most of the interaction logic. jQuery ended up in a few specific places where I was doing quick DOM manipulation and the syntax was just cleaner.&lt;/p&gt;

&lt;p&gt;I don't think there's a strong philosophical argument here. It's just that once you start writing vanilla JS properly you realize most of the things you were reaching for jQuery to do are actually not that hard.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three.js, a Blender File, and the Learning Curve I Underestimated
&lt;/h2&gt;

&lt;p&gt;The Three.js section of this build took way longer than I thought it would.&lt;/p&gt;

&lt;p&gt;Three.js is one of those libraries where the documentation is technically good and also kind of confusing if you haven't done any 3D work before. The concepts — scene, camera, renderer, geometry, material, mesh, light — they make complete sense once you get it. Before you get it, it feels like you're assembling furniture from instructions written in a different language.&lt;/p&gt;

&lt;p&gt;I used Blender to create the 3D model that lives in the portfolio. If you've never opened Blender, it is a lot. The interface alone takes a few days to get comfortable with. But for what I needed — modeling a specific object, exporting it in a format Three.js can read — it was the right tool.&lt;/p&gt;

&lt;p&gt;The thing nobody tells you about Three.js performance is that 3D on the web is heavy by default and you have to actively fight against that. Geometry complexity, texture resolution, how you're handling the render loop, whether you're correctly disposing of objects when they're not needed — all of this hits your frame rate. I ended up adding a toggle that lets users turn off the 3D effects entirely, specifically for older devices. Some people will land on the site on a five year old phone. The site should still work for them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before adding the 3D scene:&lt;/strong&gt;&lt;br&gt;
The hero section was static. Clean, but kind of flat. No real visual depth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
There's actual spatial weight to the page. The 3D element gives the viewport a sense of depth that you can't really replicate with CSS tricks alone.&lt;/p&gt;

&lt;p&gt;The trade-off is performance. I'll be honest — Three.js adds real weight to the bundle and if you don't handle it carefully your Lighthouse score will tell you. I spent time optimizing how and when the scene initializes, deferring it until after critical content loads.&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.amazonaws.com%2Fuploads%2Farticles%2F7172g5jom3qnmmnqkafs.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.amazonaws.com%2Fuploads%2Farticles%2F7172g5jom3qnmmnqkafs.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Certifications Book That Took a Weird Amount of Work
&lt;/h2&gt;

&lt;p&gt;One of the sections I'm most satisfied with is the certifications section. Instead of a standard grid of certificate images, I built a flipbook — an actual book you can page through — using TurnJS combined with TiltJS for the 3D tilt effect when you hover.&lt;/p&gt;

&lt;p&gt;TurnJS is a library that simulates page turning. It uses CSS3 transforms and JavaScript to create a page-flip animation that looks like a real book. Wiring it up to work with the actual certificate content, making it responsive, handling the edge cases around what happens when someone is on a touch device — this took more time than I expected.&lt;/p&gt;

&lt;p&gt;TiltJS sits on top of that and adds the parallax tilt effect when you move your mouse over the book. The way the two libraries interact required some careful event handling. There were bugs. There were moments where the tilt was triggering when it shouldn't, or where the page flip animation was cutting off because something in the transition timing was conflicting.&lt;/p&gt;

&lt;p&gt;But when it works — and it works now — it's genuinely one of the most distinctive things on the site. Every other developer portfolio has a grid of certificates. Mine has a book.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scroll Behavior: Lenis, IntersectionObserver, and the Scrolljacking Debate
&lt;/h2&gt;

&lt;p&gt;Smooth scroll is one of those things that sounds like a nice small detail and turns into a rabbit hole.&lt;/p&gt;

&lt;p&gt;I'm using Lenis.js for smooth scrolling. Lenis intercepts the native scroll and replaces it with a smoother, physics-based animation. The result is this buttery, almost native-app feel when you scroll through the page. It's subtle but it matters. The difference between scrolling a site with and without Lenis is the difference between dragging something across carpet versus dragging it across glass.&lt;/p&gt;

&lt;p&gt;The debate around scrolljacking is real and worth acknowledging. Scrolljacking — controlling or manipulating the scroll behavior beyond the user's direct input — has a bad reputation and for good reason. It can feel jarring, it breaks user expectations, and it's particularly bad for accessibility. I made specific choices here: the Lenis implementation I'm using follows the user's actual scroll direction and speed, it doesn't take over or redirect the scroll, it just smooths the physics. That's different from the aggressive scrolljacking you see on some agency sites where sections snap into place whether you wanted them to or not.&lt;/p&gt;

&lt;p&gt;IntersectionObserver is what drives the section animations. Elements animate in when they enter the viewport. I'm not using a library for this — it's native browser API, well supported, and honestly not that complicated once you write it a few times. The performance profile is much better than scroll event listeners, which fire constantly and are easy to abuse.&lt;/p&gt;




&lt;h2&gt;
  
  
  SignalHub: The Section I've Never Seen on Another Portfolio
&lt;/h2&gt;

&lt;p&gt;The section called SignalHub is the one I get the most questions about.&lt;/p&gt;

&lt;p&gt;Most portfolios have a contact section with a few social icons at the bottom. Facebook, GitHub, LinkedIn, maybe Twitter. That's fine. Functional. Forgettable.&lt;/p&gt;

&lt;p&gt;SignalHub is a full section built around two sides — a personal side and a professional side. It's my complete social presence, organized by context. The professional side has GitHub, LinkedIn, dev.to. The personal side has the stuff that's more me and less resume. Both sides are clean, navigable, and presented as a real part of the site rather than an afterthought footer row.&lt;/p&gt;

&lt;p&gt;The reason I built it this way is that I think there's actually a signal in &lt;em&gt;how&lt;/em&gt; a developer organizes their online presence. Showing that I've thought about context — personal vs professional, what belongs where — says something. It's also just more useful for whoever is looking at the site. If a recruiter lands on it they go to the professional side. If another developer is curious about what I'm actually like as a person they go to the other side.&lt;/p&gt;

&lt;p&gt;Is it unconventional? Yes. Did some people think it was weird when I described it? Also yes. It's still on the site.&lt;/p&gt;




&lt;h2&gt;
  
  
  Nine Sections, One Page, Zero Frameworks
&lt;/h2&gt;

&lt;p&gt;The portfolio is a single page application in the most literal sense — it's one HTML file with nine distinct sections: Home, About, Education, Skills, Certification, Blog, Contact, Projects, and SignalHub.&lt;/p&gt;

&lt;p&gt;No React. No Vue. No Next.js. Just HTML, CSS, JavaScript, and a set of libraries that handle specific things.&lt;/p&gt;

&lt;p&gt;I want to defend this choice because the developer community has a habit of treating framework usage as a marker of seriousness. If you're not using React you're not building real things, that sort of attitude. I think that's backwards.&lt;/p&gt;

&lt;p&gt;For a static portfolio site, a framework adds complexity without adding value. React's component model solves problems that a single-page portfolio doesn't have. The virtual DOM solves a reconciliation problem that doesn't exist when your content doesn't change at runtime. You're adding a build step, a node_modules folder, a mental model, and a bundle size — and none of those things make the portfolio better for the people visiting it.&lt;/p&gt;

&lt;p&gt;The cursor tracking, the trailing cursor effect, the animations — all of that is JavaScript. Not framework JavaScript. Just JavaScript.&lt;/p&gt;




&lt;h2&gt;
  
  
  SEO on a Static Site: The Part Most Portfolio Guides Skip
&lt;/h2&gt;

&lt;p&gt;This part took longer than any feature.&lt;/p&gt;

&lt;p&gt;I want to go through what's actually implemented because "I set up SEO" is a phrase people say without explaining what that means.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meta Tags and Open Graph&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every important meta tag is in the head. Open Graph tags so the site previews correctly when shared on social media. Twitter card meta. Canonical URL. Description. Keywords. These are the basics and they take maybe 30 minutes but a lot of portfolio sites don't have them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JSON-LD Structured Data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the thing most developers skip. JSON-LD is a way to embed structured data in your page that search engines can parse to understand what your page is about. For a personal portfolio, the relevant schema types are Person, WebSite, and potentially BreadcrumbList. Having this in place means Google can potentially show rich results — things like your name and links directly in the search results, not just the page title.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;llms.txt&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you haven't heard of llms.txt, it's a relatively new convention — a plain text file at the root of your site that describes your site to large language models. The idea is similar to robots.txt but for AI crawlers. I added one because I think it's going to matter more over time as AI-driven search and AI assistants become the primary way people discover content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;robots.txt and sitemap.xml&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both are present. The sitemap is submitted to both Google Search Console and Bing Webmaster Tools. The robots.txt is correctly configured — there's nothing sophisticated to block, so it's mostly permissive, but having it there properly formatted matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloudinary for Image Delivery&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Images are served from Cloudinary in WebP format with PNG fallbacks. WebP images are on average 25-35% smaller than equivalent JPEG or PNG files. When you're serving a portfolio that has project screenshots, certificate images, profile photos — that size difference accumulates. Cloudinary also gives you automatic format selection and responsive image delivery, so mobile users aren't downloading desktop-sized images.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google and Bing Indexing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The site is verified with both Google Search Console and Bing Webmaster Tools. Manual indexing requests were submitted. I know this because I did it. Not passively waiting for crawlers to find it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structured Heading Hierarchy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One H1 per page. H2s for major sections. H3s inside sections where appropriate. This isn't just SEO — it's accessibility. Screen readers navigate by heading structure. If your headings are a mess the page is a mess.&lt;/p&gt;




&lt;h2&gt;
  
  
  The "Over-Clean" Problem
&lt;/h2&gt;

&lt;p&gt;There is a thing that happens when you have full control over a codebase and you spend too much time on it. Everything starts looking a little too perfect. Every spacing value is consistent, every transition matches, every color is deliberate. And then you look at it from a distance and something feels slightly off. Too polished. Like a room that nobody actually lives in.&lt;/p&gt;

&lt;p&gt;I've had a few people describe my portfolio as "over-clean." I understand what they mean. There's something about a site that looks like it was designed in Figma and exported perfectly that can feel slightly removed. Like you're looking at a product shot rather than a person's work.&lt;/p&gt;

&lt;p&gt;I don't have a full solution for this. I've thought about adding more intentional asymmetry, rougher textures, sections that break the grid on purpose. Some of the upcoming features I'm working on — a built-in blog, a personal AI integration, a game — those might add the kind of lived-in quality that the site currently lacks.&lt;/p&gt;

&lt;p&gt;For now I'm sitting with it. Sometimes clean is clean and that's fine.&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.amazonaws.com%2Fuploads%2Farticles%2F5ujytqjp6pgyiax9l29x.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.amazonaws.com%2Fuploads%2Farticles%2F5ujytqjp6pgyiax9l29x.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Coming Next (The Honest Version)
&lt;/h2&gt;

&lt;p&gt;Here are the features I'm actively working on or thinking seriously about:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Personal AI integration&lt;/strong&gt; — an AI assistant that knows my work, my writing, my projects, and can answer questions about me. This is actually more interesting technically than it sounds because it requires some form of retrieval-augmented generation rather than just wrapping a model API call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Built-in blog&lt;/strong&gt; — not links to external posts. Articles that live inside the portfolio itself, properly rendered, indexed, and consistent with the site's design language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case studies for projects&lt;/strong&gt; — right now the project section shows what I built. The plan is to add case studies that show why I built it, what decisions I made, what I'd change. The how matters less than the thinking behind it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance and accessibility audit&lt;/strong&gt; — Lighthouse scores are okay but there's work left. WCAG 2.1 AA compliance is the target for accessibility. fetchpriority hints for above-the-fold images. Better font loading strategy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replacing the current modal with a custom one&lt;/strong&gt; — the modal system I'm using right now is borrowed. Writing my own gives me full control over the interaction model and removes an external dependency.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Thing That Actually Mattered
&lt;/h2&gt;

&lt;p&gt;145 commits to the main branch. 23 stars. 7 forks. JavaScript at 50.7% of the codebase.&lt;/p&gt;

&lt;p&gt;None of those numbers are the point.&lt;/p&gt;

&lt;p&gt;The point is that when someone asks me how the certification flipbook works, I can explain it. When someone asks why I chose Lenis over native smooth scroll, I have an actual answer. When someone asks about the SEO implementation, I don't have to guess — I built it, I know what's in there.&lt;/p&gt;

&lt;p&gt;A template can look better than what I built. Probably several of them do. But a template doesn't teach you anything except how to edit someone else's decisions. And if you're at the beginning of your career, decisions — making them, understanding them, owning them — are what you're supposed to be practicing.&lt;/p&gt;

&lt;p&gt;Build your own portfolio. Make it messy if you have to. Make decisions you'll regret later and then learn why you regret them. Put your name on something you actually built.&lt;/p&gt;

&lt;p&gt;That's the whole thing.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Stack summary:&lt;/strong&gt; HTML5, custom CSS3, Bootstrap 5 (grid only), Vanilla JS, jQuery (minimal), Three.js, Blender (3D modeling), TurnJS, TiltJS, Lenis.js, AJAX, Formspree, Cloudinary, GitHub Pages / custom domain&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repo:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev/Portfolio" rel="noopener noreferrer"&gt;ahmershahdev/Portfolio&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Find Me Across the Web
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧭 &lt;strong&gt;All links:&lt;/strong&gt; &lt;a href="https://beacons.ai/syedahmershah" rel="noopener noreferrer"&gt;Beacons&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
      <category>git</category>
      <category>nextjs</category>
      <category>node</category>
    </item>
    <item>
      <title>I Built a Production-Grade E-Commerce Platform in 3 Months — GitHub Copilot Was My Co-Founder</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Sat, 23 May 2026 20:57:12 +0000</pubDate>
      <link>https://dev.to/syedahmershah/i-built-a-production-grade-e-commerce-platform-in-3-months-github-copilot-was-my-co-founder-11m4</link>
      <guid>https://dev.to/syedahmershah/i-built-a-production-grade-e-commerce-platform-in-3-months-github-copilot-was-my-co-founder-11m4</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-05-21"&gt;GitHub Finish-Up-A-Thon Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Let me be honest with you first — when I started &lt;strong&gt;Commerza&lt;/strong&gt;, I genuinely didn't know if I would ever finish it.&lt;/p&gt;

&lt;p&gt;I'm a 19-year-old software engineering student from Pakistan. Not from some well-funded university. Not from a bootcamp in San Francisco. I'm doing a 4-year BSE at HITMS and a 3-year Advanced Diploma in Software Engineering at Aptech Pakistan, side by side, trying to become a full-stack developer with real skills — not just tutorial-following muscle memory.&lt;/p&gt;

&lt;p&gt;Commerza is a &lt;strong&gt;production-grade PHP + MySQL e-commerce platform&lt;/strong&gt;. Full storefront. Full admin panel. Real payments (COD + Stripe). Enterprise-level security — CSRF protection, Google reCAPTCHA v2 &lt;em&gt;and&lt;/em&gt; v3, rate limiting, audit logs, stock locking, SMTP failover, Argon2id password hashing, SQL injection defenses across every user-facing mutation path.&lt;/p&gt;

&lt;p&gt;The kind of stuff you'd expect from a team. Not one broke student coding at 2am.&lt;/p&gt;

&lt;p&gt;And no — it wasn't a "weekend project". This thing has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;80 PHP files&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;339 total tracked files&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;136 commits&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;PHP 62.6% | JavaScript 20.8% | CSS 15.0% | PowerShell 1.6%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stack: &lt;code&gt;HTML&lt;/code&gt; · &lt;code&gt;CSS&lt;/code&gt; · &lt;code&gt;JavaScript&lt;/code&gt; · &lt;code&gt;jQuery&lt;/code&gt; · &lt;code&gt;Bootstrap&lt;/code&gt; · &lt;code&gt;PHP&lt;/code&gt; · &lt;code&gt;MySQL&lt;/code&gt; · &lt;code&gt;JSON&lt;/code&gt; · &lt;code&gt;XML&lt;/code&gt; · &lt;code&gt;SEO&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It has a dark mode (OrangeRed + Black) and a light mode (NavyBlue + White). It has Cloudinary integration, Redis/APCu caching layers, ClamAV upload scanning, sub-admin role management, a product trash bin, coupon campaigns, review eligibility enforcement, OAuth via Google and Facebook, customer blacklists, and a CI security gate that runs on every push.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;&lt;a href="https://github.com/ahmershahdev/commerza" rel="noopener noreferrer"&gt;Commerza&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And GitHub Copilot — with Claude Sonnet 4.6, Claude Opus 4.6, and GPT-5.2-Codex — built probably &lt;strong&gt;78% of the backend&lt;/strong&gt; alongside me.&lt;/p&gt;




&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;🔗 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev/commerza" rel="noopener noreferrer"&gt;github.com/ahmershahdev/commerza&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;(Screenshots Below)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&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.amazonaws.com%2Fuploads%2Farticles%2Fvrdlz7vbuf2ecycygyyh.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.amazonaws.com%2Fuploads%2Farticles%2Fvrdlz7vbuf2ecycygyyh.png" alt="Commerza storefront homepage displaying a minimalist, high-end hero slider for premium products with clean navigation links and light mode active." width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpyyrq9kygdohd9s5r5xz.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.amazonaws.com%2Fuploads%2Farticles%2Fpyyrq9kygdohd9s5r5xz.png" alt="Commerza custom checkout system in dark mode showing form fields and a dynamic math security question fallback panel triggered on localhost when Google reCAPTCHA is inactive." width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhg972005m9f83f2n9kxp.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.amazonaws.com%2Fuploads%2Farticles%2Fhg972005m9f83f2n9kxp.png" alt="Customer order history dashboard within the Commerza user account profile showing order details, order IDs, and real-time high-value COD email verification status updates." width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxbjcxeg994w5jxwkc2sw.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.amazonaws.com%2Fuploads%2Farticles%2Fxbjcxeg994w5jxwkc2sw.png" alt="Commerza central admin dashboard UI displaying real-time e-commerce key performance indicators, total revenue, order metrics, customer counts, and a recent orders log table." width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyqf9iw3sozbpvti2md0g.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.amazonaws.com%2Fuploads%2Farticles%2Fyqf9iw3sozbpvti2md0g.png" alt="Commerza administrative management dashboard showing the custom sub-admin account creation wizard with modular role profiling options like Operations Manager and Customer Support." width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Comeback Story
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where It Started
&lt;/h3&gt;

&lt;p&gt;January 2026. I had the idea. I wanted to build something I could actually show to a client or employer — not a todo app, not a blog engine. Something &lt;em&gt;real&lt;/em&gt;. An e-commerce platform from scratch. No Laravel, no framework crutch. Raw PHP. Because I wanted to understand every layer.&lt;/p&gt;

&lt;p&gt;The first month? I was mostly doing frontend. HTML structure. CSS design system. Bootstrap grid. jQuery interactions. I wrote those by hand. Clean, methodical, slow. Every component manually. The product cards. The navbar. The cart page. The admin sidebar.&lt;/p&gt;

&lt;p&gt;You can see it in my commit history. Slow, small, frontend commits. One file at a time.&lt;/p&gt;

&lt;p&gt;Then I hit the backend wall.&lt;/p&gt;

&lt;p&gt;I stared at the PHP folder for three days. I knew PHP basics. But &lt;em&gt;production&lt;/em&gt; PHP is a different animal. PDO vs mysqli. Prepared statements everywhere, not just "when you feel like it". CSRF tokens — what are they, really, and where do they go? Argon2id vs bcrypt — does it matter for a student project? (Yes. It does.)&lt;/p&gt;

&lt;p&gt;The stuff I thought would take me "a few days" started looking like months of work. Email automation — SMTP with a failover to a backup transport? Rate limiting that doesn't break normal users? reCAPTCHA v3 with score thresholds and action validation?&lt;/p&gt;

&lt;p&gt;I'd have been done in 6-8 months. Maybe.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter Copilot
&lt;/h3&gt;

&lt;p&gt;I'd been using GitHub Copilot casually for code completion. But sometime in early February 2026, I started actually &lt;em&gt;talking&lt;/em&gt; to it. Using the agent mode. Giving it context. Describing what I needed. Letting it write entire systems.&lt;/p&gt;

&lt;p&gt;The shift was dramatic.&lt;/p&gt;

&lt;p&gt;Here's one of the first real "wow" moments. I needed SMTP failover. My plan was: try primary SMTP, if it fails, fail the email. Copilot suggested something I hadn't considered — a dual-route architecture where the primary and secondary share a duplicate-suppression check so you don't accidentally send the same email twice if both routes are responsive at once.&lt;/p&gt;

&lt;p&gt;I did not know that was a real pattern. I learned it &lt;em&gt;in the tool&lt;/em&gt;. Not from a YouTube tutorial. Not from StackOverflow. From watching Copilot write it and then asking it to explain why.&lt;/p&gt;

&lt;p&gt;The final architecture for &lt;code&gt;backend/mailer/mailer.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simplified illustration of the SMTP failover logic Copilot introduced&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;send_mail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$html_body&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$primary&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;smtp_transport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'primary'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$secondary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;smtp_transport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'fallback'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Suppress duplicate route — if both point to same host/account, skip fallback&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;same_transport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$secondary&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;attempt_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$html_body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;attempt_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$html_body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Primary failed — try fallback&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;attempt_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$secondary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$html_body&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;p&gt;Small thing. But I would not have thought of the duplicate suppression check. That detail would have caused a real bug in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Copilot Built
&lt;/h3&gt;

&lt;p&gt;Let me be specific. Here's what GitHub Copilot generated — or heavily scaffolded — with me reviewing, testing, and iterating:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email Automation System&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SMTP primary + fallback routing (&lt;code&gt;mailer.php&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Security code generation + 15-minute expiry OTP for 2FA and password resets&lt;/li&gt;
&lt;li&gt;Cart expiry reminder emails (&lt;code&gt;send_engagement_reminders.php&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Wishlist expiry reminder emails&lt;/li&gt;
&lt;li&gt;Monthly profit report emails (&lt;code&gt;monthly_profit_report.php&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Weekly analytics report emails (&lt;code&gt;weekly_analytics_report.php&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Admin Panel Systems&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coupon management (create, activate, validate, campaign control)&lt;/li&gt;
&lt;li&gt;Product review moderation with delivery-status eligibility enforcement&lt;/li&gt;
&lt;li&gt;Product trash bin with restore workflow and storefront exclusion logic&lt;/li&gt;
&lt;li&gt;Sub-admin lifecycle (invite, email verify, roles, suspend/reactivate, delete + immediate session revocation)&lt;/li&gt;
&lt;li&gt;Security event monitoring UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security Infrastructure&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google reCAPTCHA v3 verification with strict score threshold (0.65 default), action validation, hostname checking, &lt;code&gt;challenge_ts&lt;/code&gt; freshness&lt;/li&gt;
&lt;li&gt;reCAPTCHA v2 fallback when v3 isn't active for a flow&lt;/li&gt;
&lt;li&gt;Honeypot field embedded in CAPTCHA widget&lt;/li&gt;
&lt;li&gt;Fallback CAPTCHA challenge (arithmetic + knowledge, hashed answer per nonce, attempt lockout)&lt;/li&gt;
&lt;li&gt;Rate limiting across all sensitive endpoints&lt;/li&gt;
&lt;li&gt;PDO helper layer for controlled incremental migration from mysqli prepared statements&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;security_helpers.php&lt;/code&gt; — centralized Argon2id/bcrypt hashing, password policy enforcement, rehash logic&lt;/li&gt;
&lt;li&gt;CI security gate via &lt;code&gt;.github/workflows/security-gate.yml&lt;/code&gt; — static checks on every push + dynamic probes when &lt;code&gt;SECURITY_BASE_URL&lt;/code&gt; is configured&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Checkout Hardening&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stock locking with &lt;code&gt;SELECT ... FOR UPDATE&lt;/code&gt; during order placement&lt;/li&gt;
&lt;li&gt;Idempotency key consumption to block duplicate form submissions&lt;/li&gt;
&lt;li&gt;High-value COD OTP threshold (email OTP for orders above configurable limit)&lt;/li&gt;
&lt;li&gt;Refund and review blacklist enforcement across all user-facing mutation paths&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Before vs. After
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Before Copilot&lt;/th&gt;
&lt;th&gt;After Copilot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PHP files written&lt;/td&gt;
&lt;td&gt;~8 (basic CRUD)&lt;/td&gt;
&lt;td&gt;80 tracked PHP files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security posture&lt;/td&gt;
&lt;td&gt;basic input escaping&lt;/td&gt;
&lt;td&gt;3-level security model (baseline → sensitive forms → critical money paths)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Email system&lt;/td&gt;
&lt;td&gt;single PHP mail() call&lt;/td&gt;
&lt;td&gt;SMTP failover + 6 automation scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Estimated time to complete&lt;/td&gt;
&lt;td&gt;6–8 months&lt;/td&gt;
&lt;td&gt;3–4 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Things I knew I didn't know&lt;/td&gt;
&lt;td&gt;PDO vs mysqli&lt;/td&gt;
&lt;td&gt;stock locking, CSP nonces, Argon2id, idempotency keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Things I didn't know I didn't know&lt;/td&gt;
&lt;td&gt;SMTP duplicate suppression, COD OTP threshold patterns, APCu/Redis cache layering&lt;/td&gt;
&lt;td&gt;&lt;em&gt;discovered through Copilot's generated code&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last row is the real one. The things I didn't know I didn't know.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Experience with GitHub Copilot
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Models Matter
&lt;/h3&gt;

&lt;p&gt;I used three models across this project:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Sonnet 4.6&lt;/strong&gt; — my daily workhorse. Fast, accurate for PHP, good at following context across multiple files. When I was iterating quickly on storefront logic or admin UI, Sonnet was my go-to. It understood my existing codebase structure without me re-explaining every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Opus 4.6&lt;/strong&gt; — for the scary parts. When I needed the CAPTCHA hybrid system designed, or when I was trying to figure out the checkout security model (transaction boundaries, row locking, idempotency), I reached for Opus. Slower, but it reasoned through edge cases I wouldn't have caught. The "Level 1, Level 2, Level 3 security severity model" in my README — that framework came out of an Opus session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GPT-5.2-Codex&lt;/strong&gt; — I used this mostly for breakpoint testing, spotting logic flaws, checking SQL injection vectors, and validating security helpers. Different model, different angle on the same code. Like having a second pair of eyes that reads code differently. Copilot's multi-model architecture made this seamless — I could switch within the same workflow.&lt;/p&gt;

&lt;p&gt;As of April 2026, GitHub Copilot supports model selection for both Claude and Codex agents, with Claude Sonnet 4.6 and Claude Opus 4.6 available for Anthropic tasks, and GPT-5.2-Codex, GPT-5.3-Codex, and GPT-5.4 available for OpenAI Codex tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Actually Happened in Practice
&lt;/h3&gt;

&lt;p&gt;It wasn't magic. Let me be clear.&lt;/p&gt;

&lt;p&gt;I wrote every single frontend file by hand. Copilot suggestions during HTML/CSS work were mostly noise — I ignored them. The jQuery interactions, the Bootstrap grid, the storefront layouts — that's mine, manually typed.&lt;/p&gt;

&lt;p&gt;Where Copilot exploded in value was PHP systems logic. The kind of code where one missed edge case means a security hole or a race condition in checkout. The kind of code where you need to know patterns you've never been taught.&lt;/p&gt;

&lt;p&gt;A real example: I knew I needed "CSRF protection." What I didn't know was &lt;em&gt;where exactly&lt;/em&gt; to validate the token (before any database operation, not after), or that regenerating the token after each validated request is a meaningful hardening step. Copilot wrote it the right way. I read the code, asked it why, it explained. That's not just autocomplete — that's mentorship encoded into a tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I Pushed Back On
&lt;/h3&gt;

&lt;p&gt;Copilot is not always right. A few things I rejected or significantly modified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It initially generated SQL using string concatenation in a few helper queries — I pushed back and forced prepared statements everywhere&lt;/li&gt;
&lt;li&gt;One version of the reCAPTCHA logic didn't validate hostname or &lt;code&gt;challenge_ts&lt;/code&gt; — I asked for hardening and got a stricter implementation&lt;/li&gt;
&lt;li&gt;The first version of the rate limiter didn't have burst tolerance — it would have flagged fast-typing legitimate users. I caught it in testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The right model is: you're the architect. Copilot is a very fast contractor who sometimes cuts corners. Review everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  On Learning While Using AI
&lt;/h3&gt;

&lt;p&gt;Here's the thing people don't say enough: AI-assisted development taught me more than it replaced. I learned PDO, Argon2id, CSP nonces, idempotency keys, stock locking, Cloudinary server-side signing, APCu caching, and Redis connection pooling — all through reading, testing, and interrogating code that Copilot generated. If I'd been alone, I'd have written simpler code and never encountered these patterns at all.&lt;/p&gt;

&lt;p&gt;The alternative wasn't "I would have learned this from scratch." The alternative was "I would have shipped something less secure and less complete."&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.amazonaws.com%2Fuploads%2Farticles%2Fs1kmgz82vn3356lztkhr.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.amazonaws.com%2Fuploads%2Farticles%2Fs1kmgz82vn3356lztkhr.PNG" alt="GitHub Copilot agent mode in VS Code: active code generation session, PHP security helpers file open" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Commerza is archived now — May 5, 2026. I archived it not because I abandoned it, but because it reached a state I'm actually satisfied with. 339 files. 80 PHP files. 136 commits. A CI security gate. A dual-SMTP mailer. An admin panel I'd actually use.&lt;/p&gt;

&lt;p&gt;Is it perfect? No. There are things I'd change. The PDO migration is incomplete — the README says so honestly. Some admin UI pages are rougher than others. There's a lot of room to grow.&lt;/p&gt;

&lt;p&gt;But it exists. It runs. It handles real security concerns that most tutorial-based PHP projects completely ignore.&lt;/p&gt;

&lt;p&gt;That's the difference three months and GitHub Copilot made.&lt;/p&gt;

&lt;p&gt;I'm not a "vibe coder." I'm not someone who just prompts and ships. Copilot was my accelerator, my pattern library, and — genuinely — my teacher on the backend. The frontend was mine. The architecture decisions were mine. The testing, the debugging, the "wait this doesn't make sense, let me re-read the generated code at 1am" — all mine.&lt;/p&gt;

&lt;p&gt;If you're a student developer who thinks AI tools are "cheating": they're not. They're the closest thing to a senior developer pair-programming with you that most of us will ever get access to, for free. Use them intelligently. Read everything they generate. Push back when it's wrong. Ask why.&lt;/p&gt;

&lt;p&gt;That's how you build a production-grade e-commerce platform in 3 months instead of 8.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;🔗 GitHub: &lt;a href="https://github.com/ahmershahdev/commerza" rel="noopener noreferrer"&gt;github.com/ahmershahdev/commerza&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built by Syed Ahmer Shah — BSE student, HITMS BSE, Aptech ADSE, Pakistan. 2026.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Find Me Across the Web
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧭 &lt;strong&gt;All links:&lt;/strong&gt; &lt;a href="https://beacons.ai/syedahmershah" rel="noopener noreferrer"&gt;Beacons&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>php</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Antigravity &amp; WebMCP: Why Google I/O 2026 is Terrifying for Devs</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Wed, 20 May 2026 11:44:46 +0000</pubDate>
      <link>https://dev.to/syedahmershah/antigravity-webmcp-why-google-io-2026-is-terrifying-for-devs-31mb</link>
      <guid>https://dev.to/syedahmershah/antigravity-webmcp-why-google-io-2026-is-terrifying-for-devs-31mb</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-io-writing-2026-05-19"&gt;Google I/O Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"It's been 10 years since we pivoted the company to be AI first."&lt;/em&gt;&lt;br&gt;
— Sundar Pichai, Google I/O 2026 Keynote, May 19, 2026&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;I watched the Google I/O 2026 keynote. And somewhere around the part where a Google DeepMind engineer named Varun Mohan demoed an AI agent that &lt;strong&gt;built a functioning operating system from scratch — in 12 hours&lt;/strong&gt; — I kind of just... sat there staring at the screen.&lt;/p&gt;

&lt;p&gt;Not because it was cool. I mean, it &lt;em&gt;was&lt;/em&gt; cool. But because of what it quietly meant.&lt;/p&gt;

&lt;p&gt;If agents can build operating systems, what does that say about my carefully maintained full-stack skill set? What does it say about yours?&lt;/p&gt;

&lt;p&gt;Let me be honest with you. I'm a developer still learning, still grinding. I've spent time with HTML, CSS, JavaScript, Firebase, Supabase — the whole usual roadmap. And this I/O felt different from previous years. It wasn't just model benchmarks and capability updates. It felt like Google was quietly drawing a map — and the destination on that map is a world where AI agents don't &lt;em&gt;help&lt;/em&gt; developers write code.&lt;/p&gt;

&lt;p&gt;They &lt;em&gt;are&lt;/em&gt; the developers.&lt;/p&gt;

&lt;p&gt;And honestly? That question kept me up.&lt;/p&gt;




&lt;h2&gt;
  
  
  🗓️ What Actually Happened at I/O 2026 — The Short Version
&lt;/h2&gt;

&lt;p&gt;Before I get into opinions, let's be clear on the facts. Google I/O 2026 ran May 19–20 at the Shoreline Amphitheatre in Mountain View, California. Over 7,000 people attended in person. The event was livestreamed to more than 500 developer events across 100 countries.&lt;/p&gt;

&lt;p&gt;The big announcements, in order of "things that made my eye twitch":&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Announcement&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gemini 3.5 Flash&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;New flagship model for agentic workflows&lt;/td&gt;
&lt;td&gt;Outperforms Gemini 3.1 Pro, runs 4x faster than competing frontier models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Antigravity 2.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Agent-first development desktop platform&lt;/td&gt;
&lt;td&gt;Multiple autonomous AI agents working in parallel on your codebase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Antigravity CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Terminal version of Antigravity&lt;/td&gt;
&lt;td&gt;Build and orchestrate agents without leaving your terminal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Antigravity SDK&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Programmatic access to agent harness&lt;/td&gt;
&lt;td&gt;Host custom agents on your own infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Managed Agents (Gemini API)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One API call = fully provisioned agent in isolated Linux sandbox&lt;/td&gt;
&lt;td&gt;Infrastructure friction = gone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Google AI Studio updates&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native Kotlin support, Workspace integration, one-click Cloud Run deploy&lt;/td&gt;
&lt;td&gt;Build and ship full-stack apps with a single prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WebMCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Open web standard for browser-based AI agents&lt;/td&gt;
&lt;td&gt;AI agents can directly interact with your web app's JS functions and HTML forms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Firebase → Agent-native&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Firebase now integrates directly with AI Studio and Antigravity&lt;/td&gt;
&lt;td&gt;Vibe-code full-stack apps, deploy to Cloud Run with one click&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gemini Omni&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multimodal world model — any input → any output&lt;/td&gt;
&lt;td&gt;Videos, images, audio, text — all combined&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Modern Web Guidance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Expert-vetted agent skills for web dev (100+ use cases)&lt;/td&gt;
&lt;td&gt;Your agent knows web best practices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Migration Agent (Android Studio)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Migrates React Native/web/iOS to native Kotlin&lt;/td&gt;
&lt;td&gt;Weeks of migration → hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CodeMender&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AI code security agent from Google DeepMind&lt;/td&gt;
&lt;td&gt;Scans agent-generated code for vulnerabilities, auto-fixes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj510scc4uebyx40xkng.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.amazonaws.com%2Fuploads%2Farticles%2Fkj510scc4uebyx40xkng.png" alt="Antigravity desktop UI screenshot" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🤖 The Part Nobody's Talking About: Antigravity Is Not a Coding Tool
&lt;/h2&gt;

&lt;p&gt;Most people are framing Antigravity as "a better Copilot" or "Google's answer to Cursor."&lt;/p&gt;

&lt;p&gt;That's wrong.&lt;/p&gt;

&lt;p&gt;Antigravity — especially with the 2.0 update — is an &lt;strong&gt;agent orchestration runtime&lt;/strong&gt;. There's a real difference. A coding tool suggests the next line. An agent runtime &lt;em&gt;executes plans&lt;/em&gt;. It spins up subagents to work in parallel. It runs in the background. It connects to your Android builds, your Firebase project, your Cloud Run deployment. It does quality audits. It emulates user experiences. It even masks credentials automatically.&lt;/p&gt;

&lt;p&gt;Google is trying to turn Gemini from a chatbot family into a distributed agent runtime. The center of gravity is not one product. It is the stack formed by Gemini 3.5 Flash, Antigravity, Gemini Spark, AI Mode in Search, Gemini Omni, Chrome, and developer-facing managed agents.&lt;/p&gt;

&lt;p&gt;That's not a coding assistant. That's a software development lifecycle, automated.&lt;/p&gt;




&lt;h2&gt;
  
  
  💻 Let Me Show You What This Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;Here's how Managed Agents actually work using the real Gemini Interactions API. This isn't pseudocode — this is the actual documented syntax from Google's official docs as of May 19, 2026.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started with Managed Agents (Real API Syntax)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install the SDK&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Requires &lt;code&gt;@google/genai&lt;/code&gt; version &lt;strong&gt;1.33.0 or later&lt;/strong&gt; for Interactions API support.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @google/genai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Spin up a full agent with a single call&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/genai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GEMINI_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runManagedAgent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// One call = a fully provisioned Antigravity agent in a remote Linux sandbox&lt;/span&gt;
  &lt;span class="c1"&gt;// The agent reasons, uses tools, executes code, and manages files autonomously&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;antigravity-preview-05-2026&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// The Antigravity base agent&lt;/span&gt;
      &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
        Create a full REST API with Express.js that:
        1. Has /users endpoint (GET, POST, DELETE)
        2. Uses in-memory storage
        3. Includes input validation
        4. Writes unit tests with Jest
        5. Creates a README.md
        Run the tests and confirm they pass.
      `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remote&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Isolated Linux sandbox, hosted by Google&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300000&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// 5 min — agents take longer than a single prompt&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// The agent doesn't just generate code — it runs it, fixes errors, returns results&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Save these — you'll need them for the next turn&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Interaction ID:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Environment ID:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environmentId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;runManagedAgent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Continue the same session — files and state are still there&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Multi-turn: resume the exact same Linux environment&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;followUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;antigravity-preview-05-2026&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Now add JWT authentication to the existing API. Don't rewrite from scratch.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// This is what makes it powerful — the previous environment persists&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environmentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Reuse the same sandbox&lt;/span&gt;
    &lt;span class="na"&gt;previousInteractionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Continue conversation history&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300000&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;followUp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent doesn't forget. It picks up exactly where it left off — same files, same packages, same state. Like handing off to a developer who was already in the middle of the work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Note:&lt;/strong&gt; Managed Agents / Interactions API is currently in &lt;strong&gt;preview&lt;/strong&gt;. The API schema may change. For stable production work, &lt;code&gt;generateContent&lt;/code&gt; remains the recommended path — Google's own docs say so.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Modern Web Guidance — The Underrated Announcement
&lt;/h3&gt;

&lt;p&gt;This is, in my opinion, the most &lt;em&gt;slept-on&lt;/em&gt; announcement of I/O 2026. Nobody is talking about it enough.&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 with one command — works with Antigravity or any agent&lt;/span&gt;
npx modern-web-guidance &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does: it gives your coding agent a set of 100+ expert-vetted web development skills. Not just "write valid HTML." We're talking WCAG accessibility standards, Core Web Vitals, security headers, Baseline API compatibility, progressive enhancement patterns.&lt;/p&gt;

&lt;p&gt;Before this, your agent wrote &lt;em&gt;working&lt;/em&gt; code. After this, your agent writes &lt;em&gt;correct&lt;/em&gt; code.&lt;/p&gt;

&lt;p&gt;That's not a nice-to-have. That's changing what "senior developer" actually means.&lt;/p&gt;




&lt;h3&gt;
  
  
  Firebase + AI Studio: Full-Stack App in One Prompt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// You type this in Google AI Studio:

"Build a task management app where users can:
- Sign in with Google
- Create and complete tasks stored in Firestore
- Get AI-powered task prioritization
- Deploy it live"

// What happens next (this is real, not a demo):
// ✅ Firebase project scaffolded with security rules
// ✅ Authentication configured via Firebase Auth
// ✅ Firestore schema and rules written
// ✅ Firebase AI Logic integrated for prioritization
// ✅ One-click deploy to Cloud Run (free tier for first 2 apps)
// ✅ Google Workspace APIs available via natural language
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Firebase's integration with Google AI Studio now supports one-click deployment to Cloud Run — no billing required for your first two Firebase-enabled apps on the new Google Cloud Starter Tier. You can also connect your apps to Google Workspace data like Gmail, Docs, and Sheets using natural language, through a standard Firebase Auth "Sign in with Google" flow.&lt;/p&gt;

&lt;p&gt;I tried this. It generated a working expense tracker — Firestore rules, authentication flow, and a functional UI — in about 4 minutes. Did I have to tweak things? Yes. A few field names, one security rule that was too permissive. But the scaffolding was solid. Faster than writing it myself? Embarrassingly, yes.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤔 The Real Question: Are Developers Being Replaced?
&lt;/h2&gt;

&lt;p&gt;Okay. Deep breath.&lt;/p&gt;

&lt;p&gt;Let me tell you what I actually think — not the comfortable answer, not the "AI is just a tool" cope that shows up in every LinkedIn post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some developers are being replaced. Some are being upgraded. The difference is whether you understand what's happening.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Before" World (pre-2026)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You write a feature → 2 days&lt;/li&gt;
&lt;li&gt;You debug a weird edge case → 3 hours&lt;/li&gt;
&lt;li&gt;You migrate an old codebase → weeks&lt;/li&gt;
&lt;li&gt;You write tests → almost as long as the feature&lt;/li&gt;
&lt;li&gt;You deploy → configuration hell&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The "After" World (I/O 2026 and beyond)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Feature → agent does it in 20 minutes&lt;/li&gt;
&lt;li&gt;Debug → agent finds it, fixes it, verifies the fix&lt;/li&gt;
&lt;li&gt;Migration → The Android Studio migration agent turns weeks into hours&lt;/li&gt;
&lt;li&gt;Tests → auto-generated and auto-run inside the sandbox&lt;/li&gt;
&lt;li&gt;Deploy → one click, Cloud Run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So yeah. Some of the &lt;em&gt;work&lt;/em&gt; is being replaced. Specifically: the repetitive, formulaic parts.&lt;/p&gt;

&lt;p&gt;But here's what ISN'T being replaced (yet):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System design decisions&lt;/strong&gt; — WHY you're building this architecture, not just HOW&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understanding user needs&lt;/strong&gt; — translating messy human requirements into precise specs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security judgment&lt;/strong&gt; — knowing which tradeoff is acceptable and which isn't&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain context&lt;/strong&gt; — what legal, ethical, business constraints apply&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality bar&lt;/strong&gt; — recognizing when "working" ≠ "good enough to ship"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent doesn't know your company's security requirements. It doesn't know your users' edge cases. It doesn't know what scales to 1 million users. &lt;em&gt;Yet&lt;/em&gt; is doing a lot of work in that sentence.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Pros &amp;amp; Cons: Honest Assessment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ What's Actually Good
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.5 Flash speed&lt;/td&gt;
&lt;td&gt;4x faster than competing frontier models — finally usable in real workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Managed Agents removing infrastructure&lt;/td&gt;
&lt;td&gt;No more Docker config / VM setup just to run an agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Firebase → Cloud Run one-click deploy&lt;/td&gt;
&lt;td&gt;Free for first 2 apps. Removes the biggest full-stack friction point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebMCP open standard&lt;/td&gt;
&lt;td&gt;Web agents can be precise, not just "AI guessing at your DOM"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration Agent&lt;/td&gt;
&lt;td&gt;Genuinely solves a real, painful, existing problem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Antigravity CLI&lt;/td&gt;
&lt;td&gt;Terminal-first devs aren't second-class citizens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$2M XPRIZE Hackathon&lt;/td&gt;
&lt;td&gt;Largest hackathon prize pool ever. A real opportunity.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  ❌ What I'm Worried About
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Forced Gemini CLI → Antigravity CLI migration&lt;/td&gt;
&lt;td&gt;Google literally says "we encourage Gemini CLI users to migrate." Not a choice.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$100/month AI Ultra plan&lt;/td&gt;
&lt;td&gt;Who gets access to frontier AI? Developers in Pakistan? India? Nigeria? The access gap is real.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent-generated code security&lt;/td&gt;
&lt;td&gt;CodeMender catches vulnerabilities — but it's an agent checking another agent's code. Trust chains all the way down.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total Google lock-in&lt;/td&gt;
&lt;td&gt;AI Studio + Antigravity + Firebase + Cloud Run + Workspace. One ecosystem. Tightly coupled. What happens when pricing changes?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Vibe coding" quality bar&lt;/td&gt;
&lt;td&gt;Prompting a CRUD app ≠ building software that's maintainable in 2 years&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfuzfudo5mqew9l78fpb.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.amazonaws.com%2Fuploads%2Farticles%2Frfuzfudo5mqew9l78fpb.png" alt="Chrome 149 browser or WebMCP diagram" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔥 The Most Underrated Announcement: WebMCP
&lt;/h2&gt;

&lt;p&gt;Everyone is talking about Gemini 3.5 Flash. Almost nobody is talking about &lt;strong&gt;WebMCP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;WebMCP is a proposed open web standard that allows developers to expose structured tools — like JavaScript functions and HTML forms — so browser-based AI agents can execute complex tasks with greater speed, reliability, and precision. The experimental WebMCP origin trial starts in &lt;strong&gt;Chrome 149&lt;/strong&gt;, with Gemini in Chrome support coming soon.&lt;/p&gt;

&lt;p&gt;Think about what this actually means.&lt;/p&gt;

&lt;p&gt;Right now, AI agents interacting with the web are basically doing screen-scraping with extra steps. They're looking at raw HTML, guessing at intent, clicking things, and hoping it works. It's fragile. It breaks constantly.&lt;/p&gt;

&lt;p&gt;WebMCP changes that architecture. Instead of the agent &lt;em&gt;guessing&lt;/em&gt; at what your form does, you &lt;em&gt;tell&lt;/em&gt; it. It's structured. Precise. Like giving AI a clean API to your website.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// WebMCP — based on proposed spec (origin trial in Chrome 149)&lt;/span&gt;
&lt;span class="c1"&gt;// Note: exact API surface may evolve as the standard matures&lt;/span&gt;

&lt;span class="c1"&gt;// In your web app, you expose capabilities to browser AI agents:&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webmcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webmcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create_task&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Creates a new task in the project management system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;dueDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Your actual business logic here&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;taskAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_user_tasks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Retrieves all tasks for the current user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;taskAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getForCurrentUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Now a browser agent (Gemini in Chrome, etc.) can:&lt;/span&gt;
&lt;span class="c1"&gt;// "Create a high-priority task called 'Fix the login bug' due Friday"&lt;/span&gt;
&lt;span class="c1"&gt;// And it executes — precisely, through your API, not through DOM hacking.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the internet becoming agent-native. Not just a few Google apps — the &lt;em&gt;whole web&lt;/em&gt;, if developers adopt it.&lt;/p&gt;

&lt;p&gt;And the reason this matters for you as a web developer: &lt;strong&gt;the websites that expose WebMCP tools will work with AI agents. The ones that don't will be invisible to them.&lt;/strong&gt; It's a new SEO, kind of. Except instead of optimizing for Google's crawler, you're optimizing for AI agents.&lt;/p&gt;




&lt;h2&gt;
  
  
  💬 What Sundar Pichai Actually Said — And What I Think He Meant
&lt;/h2&gt;

&lt;p&gt;Pichai opened the keynote with: &lt;em&gt;"It's been 10 years since we pivoted the company to be AI first."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On the surface, that's a corporate milestone statement. But underneath it, there's an implicit message:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The first 10 years were about building the AI. The next 10 years are about the AI building everything else.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google's planned AI spending is expected to hit somewhere between &lt;strong&gt;$180 billion and $190 billion&lt;/strong&gt; this year alone. That's not a bet. That's a complete restructuring of what the company is.&lt;/p&gt;

&lt;p&gt;And for developers, that means the ground is moving under your feet whether you're watching the keynote or not.&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.amazonaws.com%2Fuploads%2Farticles%2F5dtfniq2xyg72x7nt7c9.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.amazonaws.com%2Fuploads%2Farticles%2F5dtfniq2xyg72x7nt7c9.png" alt="Screenshot of a working Firebase app or AI Studio generating code" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🧪 My Honest Hands-On Experience
&lt;/h2&gt;

&lt;p&gt;After the keynote, I actually tried things instead of just forming opinions in a vacuum:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Google AI Studio + Firebase&lt;/strong&gt;&lt;br&gt;
Built a simple expense tracker app via prompt. Firestore rules, auth flow, working UI — about 4 minutes. I had to edit the Firestore security rule for the user document (it was too open), and one of the UI components had hardcoded user IDs that needed replacing. But the scaffolding? Solid. The deploy to Cloud Run worked first try.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Modern Web Guidance&lt;/strong&gt;&lt;br&gt;
Ran &lt;code&gt;npx modern-web-guidance install&lt;/code&gt;. It pulled in a large set of expert knowledge covering web performance, accessibility, and security. I then asked the agent to "make this page accessible." It identified missing alt text, added proper ARIA roles, and noted the color contrast ratio was below WCAG 2.2 AA standard. That's not a generic suggestion. That's specificity that usually requires a senior dev to catch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Antigravity CLI (early preview)&lt;/strong&gt;&lt;br&gt;
Fast. The terminal experience is genuinely good. The credential masking is real — I tested it by deliberately putting an API key in a prompt and it masked it automatically. The agent ran terminal commands, checked output, and fixed its own mistakes mid-task. No manual intervention.&lt;/p&gt;

&lt;p&gt;The honest verdict: &lt;strong&gt;it works&lt;/strong&gt;. It's not magic. Agents still make dumb mistakes — wrong assumptions, over-eager refactors, occasional hallucinated package names. But the infrastructure is real. The speed is real. And it's moving faster than most developers are adjusting to.&lt;/p&gt;




&lt;h2&gt;
  
  
  📖 What This Means For Developers — The Uncomfortable Reflection
&lt;/h2&gt;

&lt;p&gt;There are three kinds of developers right now:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer Type A&lt;/strong&gt; — Sees AI agents and panics. Dismisses them as "hype." Keeps doing everything manually. Will be fine for a while. Then suddenly won't be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer Type B&lt;/strong&gt; — Sees AI agents and fully surrenders. Just prompts everything. Has no idea what the generated code actually does. Can't debug. Can't make architecture decisions. Produces fast, shallow work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer Type C&lt;/strong&gt; — Sees AI agents as force multipliers. Understands systems deeply. Uses agents for the mechanical work. Keeps judgment, architecture, and critical thinking in their own hands. &lt;strong&gt;This person becomes 10x more productive without becoming 10x more replaceable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I/O 2026 forced me to ask: which one am I actually building toward?&lt;/p&gt;

&lt;p&gt;Because Google didn't just release tools at this keynote. They released a vision. This is the era of agent-led development, where agents are evolving from coding assistants to intelligent collaborators capable of managing the entire software development lifecycle.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;entire&lt;/em&gt; lifecycle. Not part of it. All of it.&lt;/p&gt;

&lt;p&gt;The only way to stay relevant in that world is to own the parts agents can't: judgment, context, taste, accountability. Those aren't soft skills. Those are the new technical skills.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 What Should You Actually Do Right Now?
&lt;/h2&gt;

&lt;p&gt;Stop consuming. Start building with the new tools. Here's a concrete list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Try the Antigravity base agent&lt;/strong&gt; → &lt;a href="https://antigravity.google" rel="noopener noreferrer"&gt;antigravity.google&lt;/a&gt; — free tier available&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run a Managed Agent interaction&lt;/strong&gt; → &lt;code&gt;npm install @google/genai@1.33.0&lt;/code&gt; + the code above&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install Modern Web Guidance&lt;/strong&gt; → &lt;code&gt;npx modern-web-guidance install&lt;/code&gt; — immediate, free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build one app in AI Studio with Firebase&lt;/strong&gt; → &lt;a href="https://aistudio.google.com" rel="noopener noreferrer"&gt;aistudio.google.com&lt;/a&gt; — first 2 Cloud Run deploys free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the WebMCP spec&lt;/strong&gt; → &lt;a href="https://developer.chrome.com/docs/ai/webmcp" rel="noopener noreferrer"&gt;developer.chrome.com/docs/ai/webmcp&lt;/a&gt; — origin trial, Chrome 149&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply for the XPRIZE Hackathon&lt;/strong&gt; → &lt;a href="http://geminixprize.com" rel="noopener noreferrer"&gt;geminixprize.com&lt;/a&gt; — $2M prize pool, September finals in LA&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  ✅ Conclusion: The Map Has Changed
&lt;/h2&gt;

&lt;p&gt;I'll leave you with this.&lt;/p&gt;

&lt;p&gt;In 2016, Google said "AI first." Nobody really believed them, not fully.&lt;/p&gt;

&lt;p&gt;In 2022, ChatGPT hit. People said "AI is a tool."&lt;/p&gt;

&lt;p&gt;In 2024, agents started shipping. People said "it's not production-ready."&lt;/p&gt;

&lt;p&gt;In 2026, at I/O, a Google engineer demoed an AI building an operating system in 12 hours. People in the audience laughed, nervously.&lt;/p&gt;

&lt;p&gt;That nervous laugh is the sound of a mental model breaking.&lt;/p&gt;

&lt;p&gt;We're not in the "AI assists developers" phase anymore. I/O 2026 was a clear pivot toward an agentic AI ecosystem where intelligent systems can assist users, automate workflows, and work across apps, devices, and services with &lt;strong&gt;minimal human intervention.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Minimal. Human. Intervention.&lt;/p&gt;

&lt;p&gt;That's the destination Google put on the map at I/O 2026.&lt;/p&gt;

&lt;p&gt;The question isn't whether you agree with the direction. It's whether you're building the skills that matter at the destination — or the skills that only mattered on the way there.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 References &amp;amp; Useful Links
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🎬 Google Keynote (May 19, 2026)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.youtube.com/watch?v=wYSncx9zLIU" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👩‍💻 Developer Keynote&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.youtube.com/watch?v=aqmpZocmR8o" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🤖 What's New in Google AI&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.youtube.com/watch?v=tfoSeH63yCg" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔥 What's New in Firebase&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.youtube.com/live/lMEfqmyRMA8" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;💙 What's New in Flutter&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.youtube.com/live/3TfGKugPlpE" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;☁️ Google Cloud Live from I/O&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.youtube.com/live/l6TNXcqRQR8" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Developers Blog — Dev Keynote Recap&lt;/td&gt;
&lt;td&gt;&lt;a href="https://developers.googleblog.com/all-the-news-from-the-google-io-2026-developer-keynote/" rel="noopener noreferrer"&gt;developers.googleblog.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Blog — Developer Highlights&lt;/td&gt;
&lt;td&gt;&lt;a href="https://blog.google/innovation-and-ai/technology/developers-tools/google-io-2026-developer-highlights/" rel="noopener noreferrer"&gt;blog.google&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Introducing Managed Agents in the Gemini API&lt;/td&gt;
&lt;td&gt;&lt;a href="https://blog.google/innovation-and-ai/technology/developers-tools/managed-agents-gemini-api/" rel="noopener noreferrer"&gt;blog.google&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Firebase I/O 2026 Announcements&lt;/td&gt;
&lt;td&gt;&lt;a href="https://firebase.blog/posts/2026/05/google-io-2026-announcements/" rel="noopener noreferrer"&gt;firebase.blog&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Official Antigravity Agent Docs&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/antigravity-agent" rel="noopener noreferrer"&gt;ai.google.dev&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini Interactions API Docs&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/interactions" rel="noopener noreferrer"&gt;ai.google.dev&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebMCP Origin Trial (Chrome 149)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://developer.chrome.com/docs/ai/webmcp" rel="noopener noreferrer"&gt;developer.chrome.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modern Web Guidance&lt;/td&gt;
&lt;td&gt;&lt;a href="http://goo.gle/modern-web-guidance" rel="noopener noreferrer"&gt;goo.gle/modern-web-guidance&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build with Gemini XPRIZE Hackathon&lt;/td&gt;
&lt;td&gt;&lt;a href="http://geminixprize.com" rel="noopener noreferrer"&gt;geminixprize.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google AI Studio&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aistudio.google.com" rel="noopener noreferrer"&gt;aistudio.google.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;em&gt;Written May 20, 2026 — the day after watching Google announce that an AI built an operating system in 12 hours, and feeling the very specific emotion of "excited and deeply unsettled at the same time."&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Find Me Across the Web
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧭 &lt;strong&gt;All links:&lt;/strong&gt; &lt;a href="https://beacons.ai/syedahmershah" rel="noopener noreferrer"&gt;Beacons&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>googleiochallenge</category>
      <category>codenewbie</category>
      <category>ai</category>
    </item>
    <item>
      <title>Swapping Go for Rust: 10x Cheaper K8s Ingress</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Tue, 19 May 2026 16:59:42 +0000</pubDate>
      <link>https://dev.to/syedahmershah/swapping-go-for-rust-10x-cheaper-k8s-ingress-2b4p</link>
      <guid>https://dev.to/syedahmershah/swapping-go-for-rust-10x-cheaper-k8s-ingress-2b4p</guid>
      <description>&lt;p&gt;Let me tell you a story that starts in 2013, peaks somewhere around 2019, and ends with me staring at a $4,200 AWS bill at 11pm on a Tuesday.&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.amazonaws.com%2Fuploads%2Farticles%2Fqqbvhbh58ugge036qdb4.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.amazonaws.com%2Fuploads%2Farticles%2Fqqbvhbh58ugge036qdb4.png" alt="A timeline from Docker's launch to the growth of containers and Kubernetes adoption." width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Revolution Nobody Saw Coming
&lt;/h2&gt;

&lt;p&gt;March 2013. PyCon. A French developer named Solomon Hykes gets on stage and does a five-minute demo of something called Docker.&lt;/p&gt;

&lt;p&gt;The audience is confused. Then curious. Then the applause starts.&lt;/p&gt;

&lt;p&gt;In those five minutes, he essentially broke software deployment as everyone knew it. No more "works on my machine." No more environment hell. You take your app, you put it in a box, and that box runs &lt;em&gt;anywhere.&lt;/em&gt; Same box. Every time.&lt;/p&gt;

&lt;p&gt;The internet lost its mind.&lt;/p&gt;

&lt;p&gt;Within a year, every startup was containerizing everything. Within two, enterprises were asking their CTOs why they weren't doing it yet. Within three, Docker was valued at over a billion dollars and "containerization" stopped being a niche word.&lt;/p&gt;

&lt;p&gt;But here's the thing about revolutions — they create new problems.&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.amazonaws.com%2Fuploads%2Farticles%2Frmi6ywcud1nylr2yfec6.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.amazonaws.com%2Fuploads%2Farticles%2Frmi6ywcud1nylr2yfec6.png" alt="A side-by-side comparison of major container orchestration platforms and their strengths." width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter: The Orchestration Wars
&lt;/h2&gt;

&lt;p&gt;By 2014 you had thousands of containers. Maybe tens of thousands. And now what? How do you run them? How do you restart the ones that crash? How do you roll out updates without downtime? How do you route traffic between them?&lt;/p&gt;

&lt;p&gt;This is when it got messy. Genuinely messy.&lt;/p&gt;

&lt;p&gt;Three players showed up:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Swarm&lt;/strong&gt; — Docker's own answer. Simple. Integrated. And honestly? Pretty good. But Docker the company was making decisions that confused everyone. They kept pivoting. Swarm never got the trust it deserved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apache Mesos&lt;/strong&gt; — the enterprise option. Heavy. Complex. Battle-tested at Twitter and Airbnb scale. But you needed a PhD to configure it and the learning curve was basically a vertical wall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt; — Google's open-source version of Borg, the internal system they'd been running for over a decade. K8s dropped in 2014 and it was ugly at first. The config was verbose, the concepts were alien, the documentation was written by people who already understood it.&lt;/p&gt;

&lt;p&gt;But then something happened. Google poured resources into it. A foundation formed around it (&lt;a href="https://www.cncf.io/" rel="noopener noreferrer"&gt;CNCF&lt;/a&gt; — Cloud Native Computing Foundation, 2015). AWS, Azure, GCP all built managed versions of it. The ecosystem exploded.&lt;/p&gt;

&lt;p&gt;By 2017 the wars were effectively over.&lt;/p&gt;

&lt;p&gt;Kubernetes won. Swarm is still technically alive but nobody talks about it at conferences anymore. Mesos is mostly a ghost. K8s became the operating system of the cloud.&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.amazonaws.com%2Fuploads%2Farticles%2F3nfyyqg1rq3jpuix6knl.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.amazonaws.com%2Fuploads%2Farticles%2F3nfyyqg1rq3jpuix6knl.png" alt="Popular cloud-native technologies built around Go and its ecosystem." width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Go's Golden Era
&lt;/h2&gt;

&lt;p&gt;Here's something worth understanding: &lt;strong&gt;Kubernetes is written in Go.&lt;/strong&gt; Docker was written in Go. Traefik, Prometheus, Terraform, Consul, etcd, Helm — basically everything that runs your infrastructure today traces back to Go.&lt;/p&gt;

&lt;p&gt;This wasn't an accident.&lt;/p&gt;

&lt;p&gt;Go was designed at Google in 2007 by some of the most legendary people in computer science — Rob Pike, Ken Thompson (yes, the Unix guy), Robert Griesemer. They wanted a language that compiled fast, ran fast, handled concurrency natively, and didn't make you want to throw your laptop through a window.&lt;/p&gt;

&lt;p&gt;They got it right.&lt;/p&gt;

&lt;p&gt;Go's goroutines made writing networked, concurrent services &lt;em&gt;stupid easy.&lt;/em&gt; The toolchain was clean. The standard library was rich. You could hire people who knew it. Everything clicked.&lt;/p&gt;

&lt;p&gt;The cloud-native world standardized on Go almost by accident. It was the right language, at the right time, for the right problems.&lt;/p&gt;

&lt;p&gt;Between 2015 and 2020, if you were building infrastructure tooling and not using Go, people looked at you sideways.&lt;/p&gt;




&lt;h2&gt;
  
  
  Meanwhile, In a Mozilla Office Somewhere...
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A Mozilla employee named Graydon Hoare is working on something in his spare time. A new systems language. One that gives you C-level performance but makes memory corruption &lt;em&gt;structurally impossible.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No garbage collector. No runtime overhead. But also no dangling pointers, no buffer overflows, no use-after-free bugs — the entire class of vulnerabilities that has haunted C and C++ for fifty years.&lt;/p&gt;

&lt;p&gt;The trick? A concept called &lt;strong&gt;ownership&lt;/strong&gt;. Every piece of memory has exactly one owner. When the owner goes out of scope, the memory is freed. Not by a GC running in the background. Not "eventually." &lt;em&gt;Immediately.&lt;/em&gt; Deterministically. At compile time.&lt;/p&gt;

&lt;p&gt;Mozilla ships Rust 1.0 in May 2015. The initial reaction from the systems programming community was somewhere between skeptical and hostile. The borrow checker — the compiler mechanism that enforces ownership — felt like fighting the language more than writing it.&lt;/p&gt;

&lt;p&gt;People tried it, got confused, went back to C++ or Go.&lt;/p&gt;

&lt;p&gt;But a small group of people &lt;em&gt;got&lt;/em&gt; it. And they kept building. Quietly.&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.amazonaws.com%2Fuploads%2Farticles%2Fhvydy1651x7nfeyvh2i0.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.amazonaws.com%2Fuploads%2Farticles%2Fhvydy1651x7nfeyvh2i0.png" alt="A visualization showing Rust's growing role in modern systems infrastructure." width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Quiet Takeover
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Cloudflare has a problem.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;They're running nginx. Everywhere. nginx is written in C. It's fast, it's reliable, but it's also showing its age — the architecture doesn't handle modern HTTP patterns well, extending it is painful, and the codebase has had its share of security issues because, well, it's C.&lt;/p&gt;

&lt;p&gt;Cloudflare decides to replace it. Not patch it. &lt;em&gt;Replace it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;They write &lt;a href="https://blog.cloudflare.com/how-we-built-pingora-the-proxy-that-connects-cloudflare-to-the-internet/" rel="noopener noreferrer"&gt;Pingora&lt;/a&gt; in Rust. A full HTTP proxy, from scratch, handling &lt;strong&gt;1 trillion requests per day&lt;/strong&gt; in production.&lt;/p&gt;

&lt;p&gt;The numbers they published were obscene. Compared to nginx: 70% reduction in CPU. 67% reduction in memory. Near-zero security vulnerabilities because the entire class of memory bugs simply cannot exist in safe Rust.&lt;/p&gt;

&lt;p&gt;And they didn't stop there. By late 2025, Cloudflare went further — they rewrote FL, the actual "brain" of Cloudflare (the system that applies every customer's WAF rules, DDoS settings, and routing logic) in Rust, calling it FL2. The result: response time dropped by 10ms and overall performance went up 25%. They shut down FL1 entirely in early 2026.&lt;/p&gt;

&lt;p&gt;Then AWS announced they were writing parts of their virtualization layer in Rust. Then Microsoft said Rust was the preferred language for new systems code at the company. Then the Linux kernel — the Linux kernel, which has run on C for thirty years — &lt;a href="https://www.kernel.org/doc/html/next/rust/index.html" rel="noopener noreferrer"&gt;accepted Rust as a second language&lt;/a&gt;, with stable driver support landing in kernel 6.1.&lt;/p&gt;

&lt;p&gt;The systems programming community quietly started paying attention.&lt;/p&gt;

&lt;p&gt;And then the Go community started getting uncomfortable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Back To My Tuesday Night
&lt;/h2&gt;

&lt;p&gt;This is where I come back in.&lt;/p&gt;

&lt;p&gt;We were a mid-size startup. Not Cloudflare. Not Amazon. But we were scaling, traffic was growing, and our Kubernetes setup was running fine.&lt;/p&gt;

&lt;p&gt;That word again. Fine.&lt;/p&gt;

&lt;p&gt;We were using &lt;a href="https://traefik.io/" rel="noopener noreferrer"&gt;Traefik&lt;/a&gt; as our ingress controller. Go-based, battle-tested, the default choice for half the K8s tutorials on the internet. Three replicas, handling maybe 800 req/s at peak.&lt;/p&gt;

&lt;p&gt;I was not watching the AWS bill closely enough. That was my fault.&lt;/p&gt;

&lt;p&gt;Then I did. And I saw $4,200 for one month of ingress-related compute.&lt;/p&gt;

&lt;p&gt;I didn't say anything for thirty seconds. I just sat there. That specific feeling when a number doesn't match your mental model and your brain is trying to reconcile it.&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.amazonaws.com%2Fuploads%2Farticles%2Fq8i79kkybl5imssy9ir2.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.amazonaws.com%2Fuploads%2Farticles%2Fq8i79kkybl5imssy9ir2.png" alt="Original infrastructure setup using Traefik with multiple pods and increased memory consumption." width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Panic Phase
&lt;/h2&gt;

&lt;p&gt;I started Googling. You should never Google things when you're panicking. You come out two hours later having read about eBPF, service meshes, and someone's confident blog post from 2021 recommending something that got deprecated in 2023.&lt;/p&gt;

&lt;p&gt;What I found when I actually focused: the memory profile of our ingress layer was absurd for what we were asking it to do.&lt;/p&gt;

&lt;p&gt;Each Traefik pod idling at ~180MB RSS. Under load? Comfortably 400MB+. That's not Traefik being badly written — it isn't. It's Go's garbage collector doing what it's designed to do. The GC optimizes for latency, not memory. It keeps things around, waits for a good time to clean up, and "a good time" under constant HTTP load basically never comes.&lt;/p&gt;

&lt;p&gt;We had 3 pods × 400MB × 2 &lt;code&gt;t3.large&lt;/code&gt; nodes (because they needed the headroom) running 24/7.&lt;/p&gt;

&lt;p&gt;Do the math on AWS pricing. Then cry.&lt;/p&gt;

&lt;p&gt;Then I found the Pingora post. Read the whole thing this time. Pulled the benchmark numbers. Understood what was actually happening at the memory level in Rust vs Go.&lt;/p&gt;

&lt;p&gt;Something clicked.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Rust Hits Different Here
&lt;/h2&gt;

&lt;p&gt;Nobody says this clearly enough so I will:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For most application code, Go's GC is fine. Genuinely fine.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Writing a web API? Go. Building a CLI tool? Go. Microservices with moderate traffic? Go, easily.&lt;/p&gt;

&lt;p&gt;But a &lt;em&gt;proxy&lt;/em&gt; is a different beast. A proxy's entire job is to sit between two things and move bytes from one to the other, as fast as possible, thousands of times per second. Every request means allocations — headers, buffers, connection state. Every one of those allocations eventually needs to be freed.&lt;/p&gt;

&lt;p&gt;In Go, "eventually" is doing a lot of work in that sentence.&lt;/p&gt;

&lt;p&gt;In Rust, memory is freed the moment it goes out of scope. Not by a background process. Not on a schedule. &lt;em&gt;Structurally,&lt;/em&gt; at the language level. The compiler guarantees it.&lt;/p&gt;

&lt;p&gt;For a proxy, that's not a nice-to-have. It's the difference between flat memory usage and a profile that climbs under load and triggers GC pauses at exactly the wrong moment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/linkerd/linkerd2-proxy" rel="noopener noreferrer"&gt;linkerd2-proxy&lt;/a&gt; — the data plane for the Linkerd service mesh — is written in Rust for exactly this reason. It's running in production service meshes at serious scale. &lt;a href="https://tokio.rs/" rel="noopener noreferrer"&gt;Tokio&lt;/a&gt; — Rust's async runtime — is mature enough that they're running their own conference in 2026. The ecosystem isn't a science experiment anymore.&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.amazonaws.com%2Fuploads%2Farticles%2Fdkheqe76n08wzzg2f60y.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.amazonaws.com%2Fuploads%2Farticles%2Fdkheqe76n08wzzg2f60y.png" alt="Optimized architecture using Envoy and Rust routing services for improved efficiency." width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Migration (It Was Not Smooth, I Won't Lie)
&lt;/h2&gt;

&lt;p&gt;We didn't rewrite Traefik. We're not a systems programming shop.&lt;/p&gt;

&lt;p&gt;We moved to &lt;strong&gt;&lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt;&lt;/strong&gt; as the core proxy (C++, but with a very different memory model than Go's runtime, and a mature extensibility story) plus a small Rust service handling our custom routing logic that Traefik was previously doing in middleware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week one:&lt;/strong&gt; three outages.&lt;/p&gt;

&lt;p&gt;Not because Rust is hard (our Rust service was fine). Because Envoy's config model is completely different from Traefik's and we were copying assumptions over like fools. Traefik does a lot of magic via annotations. Envoy does nothing by magic. Everything explicit. Everything verbose. First time you see an Envoy config file you think someone is hazing you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week two:&lt;/strong&gt; stable. Genuinely stable. We kept waiting for something to explode. Nothing did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week three:&lt;/strong&gt; I pulled up the memory dashboards.&lt;/p&gt;

&lt;p&gt;I called my co-engineer over. We both stared at it for a moment.&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.amazonaws.com%2Fuploads%2Farticles%2F4y1jjns5v8dc41qvvkpf.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.amazonaws.com%2Fuploads%2Farticles%2F4y1jjns5v8dc41qvvkpf.png" alt="Performance and cost comparison showing reduced resource usage after migration." width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers (This Is The Part You Came For)
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;3x Traefik pods&lt;/li&gt;
&lt;li&gt;~380MB average RSS each&lt;/li&gt;
&lt;li&gt;CPU spikes during GC under high traffic&lt;/li&gt;
&lt;li&gt;2x &lt;code&gt;t3.large&lt;/code&gt; nodes just for ingress (2 vCPU, 8GB each)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;2x Envoy pods + Rust routing layer&lt;/li&gt;
&lt;li&gt;~40MB average RSS each&lt;/li&gt;
&lt;li&gt;CPU: completely flat. No spikes. No GC sweeps. Nothing.&lt;/li&gt;
&lt;li&gt;1x &lt;code&gt;t3.small&lt;/code&gt; node handles it without breaking a sweat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Node costs alone: from ~$340/month to ~$30/month.&lt;/p&gt;

&lt;p&gt;Factor in traffic processing, data transfer handling, reduced overhead across the board — the full picture came out to roughly &lt;strong&gt;10x cheaper.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not 10% cheaper. Not 2x. Ten times.&lt;/p&gt;

&lt;p&gt;The title isn't clickbait. I was as shocked as you are right now.&lt;/p&gt;




&lt;h2&gt;
  
  
  Should You Actually Do This?
&lt;/h2&gt;

&lt;p&gt;Real answer: &lt;strong&gt;probably not yet, unless you're bleeding money.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Operational complexity is a real cost. This migration took two engineers about three weeks including the debugging nights and the config archaeology. If Traefik is working for you and your AWS bill isn't making you spiral, leave it alone. Boring infrastructure is good infrastructure.&lt;/p&gt;

&lt;p&gt;But if your ingress layer has its own line item on your cost explorer — and you feel a specific kind of shame looking at it — the tooling exists, it's production-proven, and the math is not subtle.&lt;/p&gt;

&lt;p&gt;The Rust networking ecosystem in 2026 is not the Rust networking ecosystem of 2018. Cloudflare has replaced their entire request-handling stack with Rust. Pingora is open-source and now at v0.7.0 — it's evolved from "proxy" into what people are calling programmable network infrastructure. linkerd2-proxy has been running in production service meshes for years. Tokio is the undisputed async runtime of the ecosystem. The scary part is mostly gone. What's left is just learning.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Actual Lesson (And It's Not About Languages)
&lt;/h2&gt;

&lt;p&gt;Go didn't lose. This wasn't a rivalry with a winner.&lt;/p&gt;

&lt;p&gt;Go won the cloud infrastructure era because it was exactly right for that moment — concurrency primitives, fast compilation, readable code, a great standard library. Kubernetes exists because of Go. The cloud-native ecosystem exists because of Go.&lt;/p&gt;

&lt;p&gt;But Rust is winning the &lt;em&gt;next&lt;/em&gt; layer — the performance-critical substrate that the rest of the infrastructure runs on. Proxies. Kernels. Network dataplanes. Places where a GC isn't a tradeoff you can afford because memory is money and latency is user experience.&lt;/p&gt;

&lt;p&gt;Both can be true. A hammer is the right tool for nails. A scalpel is the right tool for surgery. Neither replaces the other.&lt;/p&gt;

&lt;p&gt;That $4,200 bill became $390.&lt;/p&gt;

&lt;p&gt;The CFO asked me what changed.&lt;/p&gt;

&lt;p&gt;I said I learned a new programming language.&lt;/p&gt;

&lt;p&gt;He nodded like he understood and immediately changed the subject.&lt;/p&gt;

&lt;p&gt;That's fine. The bill was paid. The graphs were flat. The nodes were small.&lt;/p&gt;

&lt;p&gt;Sometimes the best infrastructure is the one nobody notices.&lt;/p&gt;




&lt;h2&gt;
  
  
  Find Me Across the Web
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;strong&gt;Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧭 &lt;strong&gt;All links:&lt;/strong&gt; &lt;a href="https://beacons.ai/syedahmershah" rel="noopener noreferrer"&gt;Beacons&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>rust</category>
      <category>docker</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Gemma 4 vs Claude vs Llama: Which Model Wins for Devs</title>
      <dc:creator>Syed Ahmer Shah</dc:creator>
      <pubDate>Sun, 17 May 2026 16:27:41 +0000</pubDate>
      <link>https://dev.to/syedahmershah/gemma-4-vs-claude-vs-llama-which-model-wins-for-devs-4p9</link>
      <guid>https://dev.to/syedahmershah/gemma-4-vs-claude-vs-llama-which-model-wins-for-devs-4p9</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge: Write About Gemma 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Okay, let me be honest with you for a second.&lt;/p&gt;

&lt;p&gt;I'm tired of AI comparison posts that read like a press release had a baby with a spreadsheet. You know the ones. Big table. Green checkmarks. "Model X wins for enterprise use cases." Thanks, very useful, completely useless.&lt;/p&gt;

&lt;p&gt;So let me try something different. Let me tell you what I actually found after spending time digging into Gemma 4, Claude, and Llama 4 in 2026 — what surprised me, what annoyed me, and where each one genuinely earns your trust or loses it.&lt;/p&gt;

&lt;p&gt;Because the honest answer is: &lt;strong&gt;it depends&lt;/strong&gt;, but not in the way you think.&lt;/p&gt;




&lt;h2&gt;
  
  
  First — What Even Is Gemma 4?
&lt;/h2&gt;

&lt;p&gt;If you haven't been paying attention, Google DeepMind dropped Gemma 4 on &lt;strong&gt;April 2, 2026&lt;/strong&gt; and it quietly started breaking things.&lt;/p&gt;

&lt;p&gt;Not in a bad way. In the "wait, this runs on &lt;em&gt;what&lt;/em&gt;?" way.&lt;/p&gt;

&lt;p&gt;Gemma 4 isn't a single model. It's a family:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;E2B&lt;/strong&gt; (~2.3B effective params) — designed for phones and Raspberry Pi. Yes, literally your Pi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E4B&lt;/strong&gt; (~4.5B effective params) — the sweet spot. Runs on integrated graphics or any 8GB+ GPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;26B A4B MoE&lt;/strong&gt; — 26 billion total params, but only 3.8 billion &lt;em&gt;active&lt;/em&gt; per inference thanks to Mixture-of-Experts routing. One A100 80GB can serve it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;31B Dense&lt;/strong&gt; — the big gun. All params active, maximum quality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of it built on the same research foundations as Gemini 3. All of it released under &lt;strong&gt;Apache 2.0&lt;/strong&gt;. No MAU limits. No special permissions. No restrictive use clauses. Just: &lt;em&gt;here, use it&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That last bit matters more than people are giving it credit for.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Numbers Nobody's Contextualizing
&lt;/h2&gt;

&lt;p&gt;Let me throw some benchmarks at you, but I'm actually going to explain what they mean:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemma 4 31B on AIME 2026 (math):&lt;/strong&gt; 89.2%&lt;br&gt;&lt;br&gt;
For context, Gemma 3 27B scored 20.8% on the same test. That's a +330% jump. Not incremental. Not a rounding error. Something fundamentally changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LiveCodeBench v6:&lt;/strong&gt; 80%&lt;br&gt;&lt;br&gt;
Gemma 3 was at 29.1%. So you're looking at 175% improvement in coding benchmarks in one generation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Codeforces ELO:&lt;/strong&gt; 2,150&lt;br&gt;&lt;br&gt;
That's expert competitive programmer territory. Running locally. On your machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agentic Tool Use (τ2-bench Retail):&lt;/strong&gt; went from 6.6% to 86.4%&lt;br&gt;&lt;br&gt;
That's +1200%. The model went from basically failing at multi-step tool use to crushing it. This is the benchmark I'd bet money on being the most meaningful one for 2026 workflows.&lt;/p&gt;

&lt;p&gt;The 31B Dense model currently sits at &lt;strong&gt;#3 on the Arena AI text leaderboard&lt;/strong&gt; among all open models — outcompeting models with 20x more parameters.&lt;/p&gt;

&lt;p&gt;And look — I know benchmarks lie sometimes. I know labs cherry-pick. But when &lt;em&gt;every&lt;/em&gt; benchmark jumps by 100-300% simultaneously, that's not cherry-picking. Something real happened here.&lt;/p&gt;




&lt;h2&gt;
  
  
  Claude: The One You Pay For (And Why You Still Might)
&lt;/h2&gt;

&lt;p&gt;Let me be clear: I respect what Anthropic has built. Claude is genuinely different from most models in ways that are hard to benchmark.&lt;/p&gt;

&lt;p&gt;As of early 2026, the main Claude options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sonnet 4.6&lt;/strong&gt; — $3/$15 per million tokens. 79.6% on SWE-bench Verified.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Opus 4.6&lt;/strong&gt; — $5/$25 per million tokens. 80.8% on SWE-bench Verified.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Opus 4.7&lt;/strong&gt; — $5/$25 per million tokens. 87.6% on SWE-bench Verified. Released April 16, 2026.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gap between Sonnet 4.6 and Opus 4.6 is 1.2 percentage points on the benchmark that matters most for developers. That's it. One point. At 40% lower cost and 17% faster output. Most production teams route 80% of work to Sonnet and reserve Opus for the genuinely hard stuff.&lt;/p&gt;

&lt;p&gt;Cursor's co-founder called Sonnet 4.6 "a notable improvement over Sonnet 4.5 across the board, including long-horizon tasks." GitHub reported strong performance on complex code fixes. Cognition said it "meaningfully closed the gap with Opus on bug detection."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So what's the catch?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Claude has no weights. Full stop.&lt;/p&gt;

&lt;p&gt;You cannot run Claude locally. You cannot fine-tune it on your data. You cannot deploy it on your own infrastructure. There's no local option, no open version, nothing. It's a pure API play.&lt;/p&gt;

&lt;p&gt;Constitutional AI baked into the architecture means you will occasionally hit refusals that feel arbitrary — requests the model &lt;em&gt;could&lt;/em&gt; handle but won't. The reason-based constitution introduced in January 2026 made these responses more nuanced, but you'll still encounter them if you push edge cases.&lt;/p&gt;

&lt;p&gt;The 200K context window is solid. The 1M beta (via header) is there for Opus if you need it. But if your use case requires data sovereignty, EU compliance, or offline deployment? Claude is a non-starter. Full stop. No negotiation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Llama 4: The "Free" Option That Has Fine Print
&lt;/h2&gt;

&lt;p&gt;Meta dropped Llama 4 in early 2026 and the internet exploded. Two models released:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scout&lt;/strong&gt; — 17B active params (16 experts), &lt;strong&gt;10M context window&lt;/strong&gt;. Fits on a single H100.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maverick&lt;/strong&gt; — 17B active params (128 experts). 400B total params. The flagship.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 10 million token context window on Scout is genuinely staggering. Nothing else touches it. If you need to feed an entire codebase, years of logs, or a library of documents into a single context — Scout is the only realistic option today.&lt;/p&gt;

&lt;p&gt;Maverick is positioned as a generalist, and for everyday writing, analysis, and conversation? It's good enough that the quality gap versus paid models often doesn't justify the cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But here's what doesn't get talked about:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The benchmark gaming incident.&lt;/strong&gt; In April 2025, Meta submitted a variant called "Llama-4-Maverick-03-26-Experimental" to LMArena. It topped the leaderboard. The public release performs noticeably worse. LMSYS later acknowledged the variant wasn't labeled clearly. Meta's VP denied training on test sets. The AI community read it as benchmark gaming regardless. Until that trust is rebuilt, take any single LMArena number for Llama 4 with healthy skepticism.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The license isn't what you think.&lt;/strong&gt; It looks open. It isn't OSI-certified open source. There's a 700M MAU clause — if your service exceeds 700 million monthly active users, you need a separate Meta license. For most devs that's irrelevant. But it also means you can't legally call it Apache or MIT. Attribution requirements exist on derivatives. Enterprise legal teams in regulated industries will flag this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EU multimodal restriction.&lt;/strong&gt; Vision is unavailable for EU-domiciled licensees. Hard block.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardware reality.&lt;/strong&gt; Llama 4 Scout needs 24GB VRAM minimum even quantized. Gemma 4 E4B runs on 6-8GB. If you're on a laptop or consumer GPU, this comparison basically ends here.&lt;/p&gt;

&lt;p&gt;Llama 4 on coding specifically? It's competitive but not dominant. If your primary workload is code generation or agentic refactoring, it's not the strongest open-weight choice in 2026.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Comparison Nobody Actually Makes
&lt;/h2&gt;

&lt;p&gt;Let me put this plainly, because most posts won't:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The real trade-off isn't quality. It's the question of: *who controls the model?&lt;/strong&gt;*&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What You Need&lt;/th&gt;
&lt;th&gt;Best Pick&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Highest raw reasoning quality&lt;/td&gt;
&lt;td&gt;Claude Opus 4.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best local deployment, low VRAM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Gemma 4 E4B&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coding on a budget&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Gemma 4 31B&lt;/strong&gt; locally, or Claude Sonnet 4.6 via API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10M+ token context&lt;/td&gt;
&lt;td&gt;Llama 4 Scout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full data sovereignty&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Gemma 4&lt;/strong&gt; (Apache 2.0, no restrictions)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commercial use, no legal headaches&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Gemma 4&lt;/strong&gt; (Apache 2.0 beats Llama's custom license)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privacy-first, runs on a phone&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Gemma 4 E2B&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agentic workflows, tool use&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Gemma 4 31B&lt;/strong&gt; (86.4% on τ2-bench) or Claude Sonnet 4.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You're in the EU with vision needs&lt;/td&gt;
&lt;td&gt;Not Llama 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need fine-tuning freedom&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Gemma 4&lt;/strong&gt; or Llama 4 (not Claude)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Where Gemma 4 Actually Wins the Argument
&lt;/h2&gt;

&lt;p&gt;The thing that keeps pulling me back to Gemma 4 isn't the benchmark numbers. It's the &lt;em&gt;combination&lt;/em&gt; of things nobody else is offering together:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edge-to-server coverage under one license.&lt;/strong&gt; E2B runs on a Raspberry Pi at ~48 tokens per second on a ROG Phone 9 Pro. The 31B Dense runs on a workstation. The 26B MoE runs on a single A100. One model family. One license. One mental model for your entire stack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Apache 2.0 shift is a big deal.&lt;/strong&gt; Earlier Gemma releases had custom licenses that enterprise legal teams routinely flagged as ambiguous. Apache 2.0 means: modify it, fine-tune it, deploy it commercially, redistribute derivatives — no royalties, no MAU limits, no acceptable use policy headaches. In 2026, as companies build always-on AI agents that process customer data continuously, the licensing terms of the underlying model are a &lt;em&gt;strategic&lt;/em&gt; decision. Gemma 4 made that decision easy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multimodal natively, not bolted on.&lt;/strong&gt; Text, image, video, audio — not as separate pipeline steps, but as native capabilities built from the Gemini 3 foundation. The smaller models (E2B, E4B) support video and audio. The larger models handle all modalities. This matters for real applications, not benchmark demos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reasoning jump is real.&lt;/strong&gt; When Gemma 4 "thinks," it can produce 4,000+ tokens of reasoning before committing to an answer. The Codeforces ELO of 2,150 puts it at expert programmer level — locally, on your GPU, free.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Honest Verdict
&lt;/h2&gt;

&lt;p&gt;If I had to give you one paragraph:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Claude when you need the absolute ceiling on reasoning and you're okay with API costs, black-box architecture, and no local option.&lt;/strong&gt; Sonnet 4.6 is the value play; Opus 4.7 is for the problems that genuinely require the best thing available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Llama 4 Scout when you need the 10M token context window and you have the hardware for it.&lt;/strong&gt; For everything else, its coding performance lags and the licensing is messier than it looks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Gemma 4 when you want the freedom to actually own your AI stack.&lt;/strong&gt; Run it on a phone for edge apps, a consumer GPU for development, a workstation for production — all with the same model family, the same license, the same mental model. The performance is now genuinely competitive at frontier level. The agentic tool use numbers in 2026 suggest it's not just catching up; in specific areas, it's already leading.&lt;/p&gt;

&lt;p&gt;The era of "open source AI is just good enough to tinker with" is over.&lt;/p&gt;

&lt;p&gt;Gemma 4 31B sitting at #3 on Arena AI, outscoring models with 20x the parameter count, running on hardware you already own, under a license that puts zero friction between you and shipping — that's not a compromise. That's just the better option for most use cases.&lt;/p&gt;




&lt;p&gt;The question isn't "which model is best" anymore.&lt;/p&gt;

&lt;p&gt;The question is: &lt;strong&gt;which model fits the kind of developer you want to be?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your answer involves ownership, privacy, cost control, and the freedom to deploy wherever you want — the answer in 2026 is becoming increasingly obvious.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;References:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aurigait.com/blog/gemma-4-features-benchmarks-guide/" rel="noopener noreferrer"&gt;Gemma 4 Complete Guide 2026 — AurigaIT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@moksh.9/" rel="noopener noreferrer"&gt;Gemma 4 Benchmarks: The Numbers That Actually Matter — Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codersera.com/blog/gemma-4-vs-llama-4-local-deployment-2026/" rel="noopener noreferrer"&gt;Gemma 4 vs Llama 4: Local Deployment 2026 — CoderSera&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.the-ai-corner.com/p/claude-opus-4-7-guide-benchmarks-2026" rel="noopener noreferrer"&gt;Claude Opus 4.7 Benchmarks — The AI Corner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://claudefa.st/blog/models/claude-sonnet-4-6" rel="noopener noreferrer"&gt;Claude Sonnet 4.6 Specs — ClaudeFast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codersera.com/blog/llama-4-complete-guide-2026/" rel="noopener noreferrer"&gt;Llama 4 Complete Developer Guide 2026 — CoderSera&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.meta.com/blog/llama-4-multimodal-intelligence/" rel="noopener noreferrer"&gt;Meta Llama 4 Official Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tech-insider.org/google-gemma-4-open-model-benchmarks-2026/" rel="noopener noreferrer"&gt;Gemma 4: How a 31B Model Beats 400B Rivals — Tech Insider&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  You can find me across the web here:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;strong&gt;Read more on Medium:&lt;/strong&gt; &lt;a href="https://medium.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;Join the discussion on DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/syedahmershah"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Deep dives on Hashnode:&lt;/strong&gt; &lt;a href="https://hashnode.com/@syedahmershah" rel="noopener noreferrer"&gt;@syedahmershah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;Check my code on GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ahmershahdev" rel="noopener noreferrer"&gt;@ahmershahdev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;Connect professionally on LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧭 &lt;strong&gt;All my links in one place on Beacons:&lt;/strong&gt; &lt;a href="https://beacons.ai/syedahmershah" rel="noopener noreferrer"&gt;Syed Ahmer Shah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Visit my Portfolio Website:&lt;/strong&gt; &lt;a href="http://ahmershah.dev" rel="noopener noreferrer"&gt;ahmershah.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>gemma</category>
      <category>codenewbie</category>
    </item>
  </channel>
</rss>
