<?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: Nilesh Raut</title>
    <description>The latest articles on DEV Community by Nilesh Raut (@speaklouder).</description>
    <link>https://dev.to/speaklouder</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%2F1027180%2Fe14fdd97-a2b6-47fe-a5a1-12628b3beca2.png</url>
      <title>DEV Community: Nilesh Raut</title>
      <link>https://dev.to/speaklouder</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/speaklouder"/>
    <language>en</language>
    <item>
      <title>Why JSON.stringify Removes Undefined Values</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Mon, 01 Jun 2026 18:30:00 +0000</pubDate>
      <link>https://dev.to/speaklouder/why-jsonstringify-removes-undefined-values-dcj</link>
      <guid>https://dev.to/speaklouder/why-jsonstringify-removes-undefined-values-dcj</guid>
      <description>&lt;p&gt;You log an object before sending it to an API:&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&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;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything looks fine.&lt;/p&gt;

&lt;p&gt;Then you serialize 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&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;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"John"&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;p&gt;The &lt;code&gt;email&lt;/code&gt; field disappears completely.&lt;/p&gt;

&lt;p&gt;No error.&lt;/p&gt;

&lt;p&gt;No warning.&lt;/p&gt;

&lt;p&gt;No indication that data was removed.&lt;/p&gt;

&lt;p&gt;This behavior surprises many developers the first time they encounter it, especially when debugging API payloads or caching systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;JSON.stringify()&lt;/code&gt; does not preserve &lt;code&gt;undefined&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;Consider:&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;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;john&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"john"&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;p&gt;The properties with &lt;code&gt;undefined&lt;/code&gt; values are omitted entirely.&lt;/p&gt;

&lt;p&gt;This can create unexpected behavior when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending API requests&lt;/li&gt;
&lt;li&gt;Updating database records&lt;/li&gt;
&lt;li&gt;Caching objects&lt;/li&gt;
&lt;li&gt;Comparing payloads&lt;/li&gt;
&lt;li&gt;Generating audit logs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why It Happens
&lt;/h2&gt;

&lt;p&gt;The behavior comes from the JSON specification itself.&lt;/p&gt;

&lt;p&gt;JSON supports only a limited set of data types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;String&lt;/li&gt;
&lt;li&gt;Number&lt;/li&gt;
&lt;li&gt;Boolean&lt;/li&gt;
&lt;li&gt;Null&lt;/li&gt;
&lt;li&gt;Object&lt;/li&gt;
&lt;li&gt;Array&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;undefined&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Functions&lt;/li&gt;
&lt;li&gt;Symbols&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because &lt;code&gt;undefined&lt;/code&gt; is not a valid JSON value, &lt;code&gt;JSON.stringify()&lt;/code&gt; excludes it from objects.&lt;/p&gt;

&lt;p&gt;Example:&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;data&lt;/span&gt; &lt;span class="o"&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;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"John"&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;p&gt;The property is removed because JSON has no representation for &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Imagine a profile update API.&lt;/p&gt;

&lt;p&gt;Frontend payload:&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;updateData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Serialized request:&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Produces:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"firstName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&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;p&gt;The backend never receives &lt;code&gt;lastName&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now the server cannot distinguish between:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&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="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both become:&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="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This distinction matters in partial update operations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Production Ready Solution
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Convert Undefined to Null
&lt;/h2&gt;

&lt;p&gt;If you need fields to remain present, explicitly convert them.&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;payload&lt;/span&gt; &lt;span class="o"&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;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;json&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;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&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;value&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="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;p&gt;The field remains visible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Create a Reusable Serializer
&lt;/h2&gt;

&lt;p&gt;In larger codebases, repeating replacer functions becomes messy.&lt;/p&gt;

&lt;p&gt;A helper works 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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;safeStringify&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&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;stringify&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&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;value&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="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&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;Usage:&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;safeStringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps behavior consistent across services.&lt;/p&gt;




&lt;h2&gt;
  
  
  Define Clear API Semantics
&lt;/h2&gt;

&lt;p&gt;In production APIs, it's important to define what each value means.&lt;/p&gt;

&lt;p&gt;For example:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;might mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;while&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="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;might mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leave email unchanged&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without clear rules, clients and servers often interpret missing fields differently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Validate Before Serialization
&lt;/h2&gt;

&lt;p&gt;Sometimes the best solution is removing invalid data intentionally.&lt;/p&gt;

&lt;p&gt;Example:&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;function&lt;/span&gt; &lt;span class="nf"&gt;removeUndefined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&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="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&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;value&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&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;cleaned&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;removeUndefined&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the omission is explicit instead of happening silently.&lt;/p&gt;




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

&lt;h2&gt;
  
  
  Assuming Undefined Becomes Null
&lt;/h2&gt;

&lt;p&gt;Many developers expect:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to become:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;p&gt;That never happens automatically.&lt;/p&gt;

&lt;p&gt;The property is removed entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Debugging the Wrong Object
&lt;/h2&gt;

&lt;p&gt;This is common:&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="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;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;shows:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;removes the field.&lt;/p&gt;

&lt;p&gt;Developers often inspect the original object and assume the serialized payload contains the same data.&lt;/p&gt;

&lt;p&gt;Always inspect the final JSON string.&lt;/p&gt;




&lt;h2&gt;
  
  
  Losing Fields During PATCH Requests
&lt;/h2&gt;

&lt;p&gt;Suppose a frontend sends:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After serialization:&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="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend may interpret this as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No changes requested&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;instead of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove phone number&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can lead to subtle update bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Forgetting Nested Objects
&lt;/h2&gt;

&lt;p&gt;The behavior applies recursively.&lt;/p&gt;

&lt;p&gt;Example:&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;bio&lt;/span&gt;&lt;span class="p"&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;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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&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;Output:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"profile"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nested properties disappear as well.&lt;/p&gt;




&lt;h2&gt;
  
  
  Debugging Tips
&lt;/h2&gt;

&lt;p&gt;When data seems to vanish during API calls, check the serialized payload first.&lt;/p&gt;




&lt;h2&gt;
  
  
  Log the Actual JSON
&lt;/h2&gt;

&lt;p&gt;Instead of:&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="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;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;use:&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="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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reveals exactly what will be transmitted.&lt;/p&gt;




&lt;h2&gt;
  
  
  Compare Before and After
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&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;Original:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&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;Serialized:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&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;The difference is often immediately obvious.&lt;/p&gt;




&lt;h2&gt;
  
  
  Inspect Network Requests
&lt;/h2&gt;

&lt;p&gt;In browser developer tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open Network tab&lt;/li&gt;
&lt;li&gt;Select request&lt;/li&gt;
&lt;li&gt;Check Request Payload&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many developers spend hours debugging backend code when the field was already removed by &lt;code&gt;JSON.stringify()&lt;/code&gt; on the client.&lt;/p&gt;




&lt;h2&gt;
  
  
  Watch for ORM Updates
&lt;/h2&gt;

&lt;p&gt;Some ORMs treat:&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="kc"&gt;null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&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="kc"&gt;undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;very differently.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB drivers&lt;/li&gt;
&lt;li&gt;Prisma&lt;/li&gt;
&lt;li&gt;Sequelize&lt;/li&gt;
&lt;li&gt;TypeORM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Verify how your persistence layer handles missing properties versus explicit null values.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance Considerations
&lt;/h2&gt;

&lt;p&gt;The default &lt;code&gt;JSON.stringify()&lt;/code&gt; implementation is highly optimized.&lt;/p&gt;

&lt;p&gt;Using a replacer function:&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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;replacer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;introduces additional processing because every property is inspected.&lt;/p&gt;

&lt;p&gt;For normal API payloads, the overhead is negligible.&lt;/p&gt;

&lt;p&gt;For very large objects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache transformed objects when possible&lt;/li&gt;
&lt;li&gt;Avoid unnecessary serialization cycles&lt;/li&gt;
&lt;li&gt;Benchmark large datasets before introducing custom replacers everywhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In most production systems, correctness matters far more than the tiny performance cost.&lt;/p&gt;




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

&lt;p&gt;&lt;code&gt;JSON.stringify()&lt;/code&gt; is not removing &lt;code&gt;undefined&lt;/code&gt; values by accident.&lt;/p&gt;

&lt;p&gt;It's following the JSON specification.&lt;/p&gt;

&lt;p&gt;The key thing to remember is:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes:&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="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;not:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;p&gt;Whenever a field must remain visible after serialization, convert &lt;code&gt;undefined&lt;/code&gt; to a valid JSON value such as &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Understanding this behavior can save a surprising amount of debugging time, especially when working with APIs, databases, caching layers, and distributed systems where missing fields and null values often have very different meanings.&lt;/p&gt;

&lt;p&gt;For more JavaScript and Node.js debugging articles based on real production issues, I occasionally publish deep dives on &lt;a href="https://nileshblog.tech" rel="noopener noreferrer"&gt;NileshBlog&lt;/a&gt; and &lt;a href="https://www.technilesh.com" rel="noopener noreferrer"&gt;TechNilesh&lt;/a&gt; when a bug is interesting enough to document.&lt;/p&gt;

</description>
      <category>node</category>
      <category>tutorial</category>
      <category>javascript</category>
      <category>learning</category>
    </item>
    <item>
      <title>Error: Cannot Set Headers After They Are Sent to the Client</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Sun, 31 May 2026 18:30:00 +0000</pubDate>
      <link>https://dev.to/speaklouder/error-cannot-set-headers-after-they-are-sent-to-the-client-j7a</link>
      <guid>https://dev.to/speaklouder/error-cannot-set-headers-after-they-are-sent-to-the-client-j7a</guid>
      <description>&lt;h1&gt;
  
  
  Error: Cannot Set Headers After They Are Sent to the Client
&lt;/h1&gt;

&lt;p&gt;If you've built APIs with Express for any length of time, you've probably seen this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error &lt;span class="o"&gt;[&lt;/span&gt;ERR_HTTP_HEADERS_SENT]: Cannot &lt;span class="nb"&gt;set &lt;/span&gt;headers after they are sent to the client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Cannot &lt;span class="nb"&gt;set &lt;/span&gt;headers after they are sent to the client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frustrating part is that the application often works for some requests and fails only under specific conditions.&lt;/p&gt;

&lt;p&gt;This error is almost always caused by sending multiple responses for the same request.&lt;/p&gt;

&lt;p&gt;Let's break down why it happens and how to prevent it in production code.&lt;/p&gt;




&lt;h1&gt;
  
  
  Problem
&lt;/h1&gt;

&lt;p&gt;Consider this Express route:&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="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="s2"&gt;/users/:id&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="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;req&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="nx"&gt;id&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;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User ID required&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;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="na"&gt;id&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;params&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks harmless.&lt;/p&gt;

&lt;p&gt;But if the first response is sent, Express continues executing the remaining code.&lt;/p&gt;

&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error &lt;span class="o"&gt;[&lt;/span&gt;ERR_HTTP_HEADERS_SENT]: Cannot &lt;span class="nb"&gt;set &lt;/span&gt;headers after they are sent to the client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server attempts to send two responses for a single request.&lt;/p&gt;

&lt;p&gt;HTTP doesn't allow that.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why It Happens
&lt;/h1&gt;

&lt;p&gt;A request can only receive one response.&lt;/p&gt;

&lt;p&gt;Once Express sends:&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the HTTP headers are already transmitted.&lt;/p&gt;

&lt;p&gt;Any attempt to modify headers or send another response will trigger the error.&lt;/p&gt;

&lt;p&gt;In production systems, this usually happens because of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing return statements&lt;/li&gt;
&lt;li&gt;Multiple async operations&lt;/li&gt;
&lt;li&gt;Duplicate error handling&lt;/li&gt;
&lt;li&gt;Middleware issues&lt;/li&gt;
&lt;li&gt;Promise and callback mixing&lt;/li&gt;
&lt;li&gt;Race conditions&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Example
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Missing Return Statement
&lt;/h2&gt;

&lt;p&gt;This is the most common cause.&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="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="s2"&gt;/profile&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="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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&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;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized&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;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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&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;If &lt;code&gt;req.user&lt;/code&gt; is missing:&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="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;401&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;runs first.&lt;/p&gt;

&lt;p&gt;Then:&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="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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;runs immediately afterward.&lt;/p&gt;

&lt;p&gt;Two responses.&lt;/p&gt;

&lt;p&gt;One request.&lt;/p&gt;

&lt;p&gt;Crash.&lt;/p&gt;




&lt;h2&gt;
  
  
  Correct Version
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&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="s2"&gt;/profile&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="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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&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="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;401&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized&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="k"&gt;return&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&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;The return statement stops execution.&lt;/p&gt;




&lt;h1&gt;
  
  
  Production Ready Solution
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Always Return After Sending a Response
&lt;/h2&gt;

&lt;p&gt;Bad:&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;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;user&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;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User not found&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;Good:&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;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;user&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="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;404&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User not found&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;This simple habit prevents countless bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Centralize Error Handling
&lt;/h2&gt;

&lt;p&gt;Instead of sending responses everywhere:&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// logic&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;error&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;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;error&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a centralized error middleware:&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="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="nx"&gt;err&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="nx"&gt;next&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;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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Internal Server 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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&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;next&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;This reduces duplicate response logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Use Async/Await Properly
&lt;/h2&gt;

&lt;p&gt;Problem:&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="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="s2"&gt;/users/:id&lt;/span&gt;&lt;span class="dl"&gt;"&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;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;user&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;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&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;params&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="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;user&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;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not found&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;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;user&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;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="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="s2"&gt;/users/:id&lt;/span&gt;&lt;span class="dl"&gt;"&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;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;user&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;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&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;params&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="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;user&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="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;404&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not found&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="k"&gt;return&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;user&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;h2&gt;
  
  
  Check Before Responding
&lt;/h2&gt;

&lt;p&gt;Sometimes third-party libraries may already send a response.&lt;/p&gt;

&lt;p&gt;Express exposes:&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headersSent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&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;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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headersSent&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;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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unexpected 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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful as a safeguard, but not a substitute for fixing the root cause.&lt;/p&gt;




&lt;h1&gt;
  
  
  Common Mistakes
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Sending a Response Inside a Loop
&lt;/h2&gt;

&lt;p&gt;Bad:&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="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&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;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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&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;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Inactive user&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loop may attempt multiple responses.&lt;/p&gt;

&lt;p&gt;Use validation before responding.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mixing Callbacks and Async/Await
&lt;/h2&gt;

&lt;p&gt;A production bug I encountered involved code like:&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="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="s2"&gt;/data&lt;/span&gt;&lt;span class="dl"&gt;"&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;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="nx"&gt;database&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="nx"&gt;sql&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="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="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;err&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;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="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="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="na"&gt;success&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The callback may execute after the success response.&lt;/p&gt;

&lt;p&gt;Now two responses are possible.&lt;/p&gt;

&lt;p&gt;Choose one style:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Async/await&lt;/li&gt;
&lt;li&gt;Promises&lt;/li&gt;
&lt;li&gt;Callbacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid mixing them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Calling Next() After Responding
&lt;/h2&gt;

&lt;p&gt;Bad:&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="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="na"&gt;success&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="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next middleware may attempt another response.&lt;/p&gt;

&lt;p&gt;Instead:&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;return&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="na"&gt;success&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Duplicate Catch Blocks
&lt;/h2&gt;

&lt;p&gt;Another common issue:&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// code&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="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="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;throw&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The thrown error may reach another handler that also sends a response.&lt;/p&gt;

&lt;p&gt;Now the request gets processed twice.&lt;/p&gt;




&lt;h1&gt;
  
  
  Debugging Tips
&lt;/h1&gt;

&lt;p&gt;When this error appears in logs, don't start searching the entire codebase.&lt;/p&gt;

&lt;p&gt;Follow a systematic approach.&lt;/p&gt;




&lt;h2&gt;
  
  
  Log Every Response
&lt;/h2&gt;

&lt;p&gt;Temporarily add:&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="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="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="nx"&gt;next&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;originalJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Response Sent:&lt;/span&gt;&lt;span class="dl"&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;originalUrl&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;originalJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;next&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 quickly reveals duplicate response paths.&lt;/p&gt;




&lt;h2&gt;
  
  
  Check Stack Traces Carefully
&lt;/h2&gt;

&lt;p&gt;Most developers only read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Cannot &lt;span class="nb"&gt;set &lt;/span&gt;headers after they are sent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The useful information is usually lower in the stack trace.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;at ServerResponse.setHeader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then identify the second response location.&lt;/p&gt;




&lt;h2&gt;
  
  
  Search for Response Methods
&lt;/h2&gt;

&lt;p&gt;Search the route for:&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&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="nx"&gt;json&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="nx"&gt;redirect&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="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If more than one execution path reaches these methods, you've found the problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Add Headers-Sent Logging
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headersSent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;before sending responses.&lt;/p&gt;

&lt;p&gt;If it prints:&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="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;another part of the application already responded.&lt;/p&gt;




&lt;h1&gt;
  
  
  Performance Considerations
&lt;/h1&gt;

&lt;p&gt;Beyond crashes, duplicate response logic wastes resources.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unnecessary database queries&lt;/li&gt;
&lt;li&gt;Extra Redis lookups&lt;/li&gt;
&lt;li&gt;Duplicate API calls&lt;/li&gt;
&lt;li&gt;Additional CPU work&lt;/li&gt;
&lt;li&gt;Increased response latency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A properly structured request handler should exit immediately after sending a response.&lt;/p&gt;

&lt;p&gt;This keeps request processing predictable and efficient.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;The "Cannot Set Headers After They Are Sent to the Client" error has a simple root cause:&lt;/p&gt;

&lt;p&gt;A request received more than one response.&lt;/p&gt;

&lt;p&gt;The fix is usually one of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add missing return statements&lt;/li&gt;
&lt;li&gt;Avoid multiple response paths&lt;/li&gt;
&lt;li&gt;Use centralized error handling&lt;/li&gt;
&lt;li&gt;Don't mix callbacks and async/await&lt;/li&gt;
&lt;li&gt;Stop middleware execution after responding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whenever I review Express code, one of the first things I check is whether every response path exits cleanly. That single habit prevents a large percentage of production API bugs before they ever reach users.&lt;/p&gt;

&lt;p&gt;For deeper Node.js debugging patterns and backend engineering articles, I occasionally publish practical production notes on &lt;a href="https://nileshblog.tech" rel="noopener noreferrer"&gt;NileshBlog&lt;/a&gt;, &lt;a href="https://prompts.nileshblog.tech" rel="noopener noreferrer"&gt;Prompts&lt;/a&gt; and &lt;a href="https://www.technilesh.com" rel="noopener noreferrer"&gt;Technilesh&lt;/a&gt;when a real-world issue is worth documenting.&lt;/p&gt;

</description>
      <category>node</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Fix EADDRINUSE: Port Already in Use</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Sun, 31 May 2026 11:17:26 +0000</pubDate>
      <link>https://dev.to/speaklouder/how-to-fix-eaddrinuse-port-already-in-use-426e</link>
      <guid>https://dev.to/speaklouder/how-to-fix-eaddrinuse-port-already-in-use-426e</guid>
      <description>&lt;p&gt;If you've worked with Node.js long enough, you've probably seen this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error: listen EADDRINUSE: address already &lt;span class="k"&gt;in &lt;/span&gt;use :::3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error: listen EADDRINUSE: address already &lt;span class="k"&gt;in &lt;/span&gt;use 0.0.0.0:5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your application refuses to start because the port you're trying to bind is already occupied.&lt;/p&gt;

&lt;p&gt;This is one of the most common issues developers encounter during local development and deployments.&lt;/p&gt;

&lt;p&gt;Let's fix it properly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;You start your Node.js server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of launching successfully, Node crashes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error: listen EADDRINUSE: address already &lt;span class="k"&gt;in &lt;/span&gt;use :::3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, only one process can listen on a specific port.&lt;/p&gt;

&lt;p&gt;If another process already owns that port, Node throws the EADDRINUSE error and exits.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why It Happens
&lt;/h2&gt;

&lt;p&gt;In production and development environments, this usually happens for one of these reasons:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Another Node.js process is already running
&lt;/h3&gt;

&lt;p&gt;You accidentally started the application twice.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in another terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both attempt to bind to port 3000.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. A crashed process didn't release the port
&lt;/h3&gt;

&lt;p&gt;This happens surprisingly often during development.&lt;/p&gt;

&lt;p&gt;You close the terminal but the process remains alive in the background.&lt;/p&gt;

&lt;p&gt;The port stays occupied.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Another application is using the port
&lt;/h3&gt;

&lt;p&gt;Common examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker containers&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;Another microservice&lt;/li&gt;
&lt;li&gt;Local development tools&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Multiple containers mapped to the same host port
&lt;/h3&gt;

&lt;p&gt;Docker example:&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;ports&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;3000:3000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two containers trying to expose port 3000 on the host will conflict.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Consider a simple Express application:&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="s2"&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="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="o"&gt;=&amp;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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server running&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;Start it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node app.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now start it again in another terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node app.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error: listen EADDRINUSE: address already &lt;span class="k"&gt;in &lt;/span&gt;use :::3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first process already owns the port.&lt;/p&gt;




&lt;h2&gt;
  
  
  Production Ready Solution
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Step 1: Identify Which Process Owns the Port
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Linux / macOS
&lt;/h3&gt;

&lt;p&gt;Find the process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsof &lt;span class="nt"&gt;-i&lt;/span&gt; :3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;COMMAND   PID USER
node     8234 dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Alternative
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;netstat &lt;span class="nt"&gt;-tulpn&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;netstat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ano&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;findstr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;3000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;TCP&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;0.0.0.0:3000&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;LISTENING&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;12345&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Locate the process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;tasklist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;findstr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;12345&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: Kill the Process
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Linux / macOS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt; 8234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;taskkill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/PID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;12345&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/F&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The port becomes available immediately.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Handle the Error Gracefully
&lt;/h2&gt;

&lt;p&gt;Production applications should not crash without useful logs.&lt;/p&gt;

&lt;p&gt;Example:&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;PORT&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;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&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;server&lt;/span&gt; &lt;span class="o"&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="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&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;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="s2"&gt;`Running on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&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="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&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="s2"&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="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;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EADDRINUSE&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; already in use`&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="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&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="k"&gt;throw&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes troubleshooting much easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Use Environment Variables
&lt;/h2&gt;

&lt;p&gt;Hardcoding ports causes unnecessary conflicts.&lt;/p&gt;

&lt;p&gt;Bad:&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="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;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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PORT&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;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&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="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run:&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="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5000 node app.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This becomes especially useful when running multiple services locally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Auto-Detect an Available Port
&lt;/h2&gt;

&lt;p&gt;For internal tools and development environments:&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;getPort&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="s2"&gt;get-port&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&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;getPort&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="mi"&gt;3000&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="nx"&gt;port&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;The application automatically chooses an available port.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  Killing the Wrong Process
&lt;/h3&gt;

&lt;p&gt;Many developers immediately run:&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="nb"&gt;kill&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt; &amp;lt;pid&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without verifying what owns the port.&lt;/p&gt;

&lt;p&gt;Always inspect first.&lt;/p&gt;

&lt;p&gt;I've seen developers accidentally terminate databases, Redis instances, and even production services on shared servers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Assuming the Port Is Free
&lt;/h2&gt;

&lt;p&gt;Just because a terminal was closed doesn't mean the process stopped.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsof &lt;span class="nt"&gt;-i&lt;/span&gt; :3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;before making assumptions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hardcoding Ports Everywhere
&lt;/h2&gt;

&lt;p&gt;Large projects often contain:&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="mi"&gt;3000&lt;/span&gt;
&lt;span class="mi"&gt;5000&lt;/span&gt;
&lt;span class="mi"&gt;8000&lt;/span&gt;
&lt;span class="mi"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;scattered throughout the codebase.&lt;/p&gt;

&lt;p&gt;Use environment variables instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ignoring Docker Port Mapping
&lt;/h2&gt;

&lt;p&gt;A common issue:&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;service-a&lt;/span&gt;&lt;span class="pi"&gt;:&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;

&lt;span class="na"&gt;service-b&lt;/span&gt;&lt;span class="pi"&gt;:&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker won't allow both containers to bind the same host port.&lt;/p&gt;

&lt;p&gt;Assign unique host ports.&lt;/p&gt;




&lt;h2&gt;
  
  
  Debugging Tips
&lt;/h2&gt;

&lt;p&gt;When EADDRINUSE appears repeatedly, I usually follow this checklist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify the owning process
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsof &lt;span class="nt"&gt;-i&lt;/span&gt; :3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Check background Node processes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps aux | &lt;span class="nb"&gt;grep &lt;/span&gt;node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll often find forgotten development servers.&lt;/p&gt;




&lt;h3&gt;
  
  
  Check Docker containers
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Look for containers exposing the conflicting port.&lt;/p&gt;




&lt;h3&gt;
  
  
  Check PM2
&lt;/h3&gt;

&lt;p&gt;If you're using PM2:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;A previously deployed process may still be running.&lt;/p&gt;




&lt;h3&gt;
  
  
  Check startup scripts
&lt;/h3&gt;

&lt;p&gt;Sometimes systemd, PM2, Docker Compose, or Kubernetes automatically restart processes after they're killed.&lt;/p&gt;

&lt;p&gt;The port immediately becomes occupied again.&lt;/p&gt;

&lt;p&gt;Verify what's managing the service.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance Considerations
&lt;/h2&gt;

&lt;p&gt;Repeatedly spawning and killing processes during development can leave orphaned processes consuming memory and CPU.&lt;/p&gt;

&lt;p&gt;A few recommendations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use process managers responsibly&lt;/li&gt;
&lt;li&gt;Avoid multiple watchers running simultaneously&lt;/li&gt;
&lt;li&gt;Shut down servers gracefully&lt;/li&gt;
&lt;li&gt;Monitor active processes regularly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Express applications, graceful shutdown looks like 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="nx"&gt;process&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="s2"&gt;SIGTERM&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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;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;Server closed&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="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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;This helps release ports cleanly.&lt;/p&gt;




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

&lt;p&gt;EADDRINUSE isn't really a Node.js problem.&lt;/p&gt;

&lt;p&gt;It's an operating system telling you that another process already owns the network port.&lt;/p&gt;

&lt;p&gt;The fastest way to solve it is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify the process&lt;/li&gt;
&lt;li&gt;Verify it's safe to stop&lt;/li&gt;
&lt;li&gt;Kill it if necessary&lt;/li&gt;
&lt;li&gt;Use configurable ports&lt;/li&gt;
&lt;li&gt;Add proper error handling&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Those five steps eliminate most port-related startup issues in both local development and production environments.&lt;/p&gt;

&lt;p&gt;If you're building backend systems regularly, keeping a small troubleshooting reference for common Node.js errors can save hours over time. I maintain similar engineering notes across projects and occasionally publish deeper backend debugging guides on &lt;a href="https://nileshblog.tech" rel="noopener noreferrer"&gt;NileshBlog.Tech&lt;/a&gt; and &lt;a href="https://www.technilesh.com" rel="noopener noreferrer"&gt;TechNilesh&lt;/a&gt; when a production issue is worth documenting.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>tutorial</category>
      <category>resources</category>
    </item>
    <item>
      <title>Hot To Run LLMs Locally</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Thu, 21 May 2026 15:34:05 +0000</pubDate>
      <link>https://dev.to/speaklouder/hot-to-run-llms-locally-l3c</link>
      <guid>https://dev.to/speaklouder/hot-to-run-llms-locally-l3c</guid>
      <description>&lt;p&gt;If you are using Claude API, OpenAI API, Cursor, or AI coding tools daily, your API bill can grow very fast.&lt;/p&gt;

&lt;p&gt;A lot of developers are now moving to local LLM setups because they want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lower AI costs&lt;/li&gt;
&lt;li&gt;Offline AI access&lt;/li&gt;
&lt;li&gt;Better privacy&lt;/li&gt;
&lt;li&gt;Faster experimentation&lt;/li&gt;
&lt;li&gt;No API limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The good news is:&lt;/p&gt;

&lt;p&gt;You can now run powerful AI models directly on your laptop using tools like Ollama (&lt;a href="https://nileshblog.tech/run-llm-locally-reduce-openai-claude-api-costs/" rel="noopener noreferrer"&gt;run llm locally&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This setup works great for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coding help&lt;/li&gt;
&lt;li&gt;Refactoring&lt;/li&gt;
&lt;li&gt;Learning&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;AI chat&lt;/li&gt;
&lt;li&gt;Small local agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s set it up step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Install Ollama
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ollama.com/download" rel="noopener noreferrer"&gt;Download Ollama&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install it normally like any software.&lt;/p&gt;

&lt;p&gt;After installation, open CMD or Terminal and check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see a version number, it is installed correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Download Your First AI Model
&lt;/h2&gt;

&lt;p&gt;Now pull a model locally.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull llama3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or for coding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull qwen2.5-coder:7b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first download may take a few minutes because models are several GB in size.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Run the Model
&lt;/h2&gt;

&lt;p&gt;Start chatting with the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run llama3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&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="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; Explain Docker &lt;span class="k"&gt;in &lt;/span&gt;simple words
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have a local AI assistant running directly on your machine.&lt;/p&gt;

&lt;p&gt;No API required.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Use It Inside VS Code
&lt;/h2&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Continue.dev&lt;/li&gt;
&lt;li&gt;Cline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both work with Ollama locally.&lt;/p&gt;

&lt;p&gt;In Continue.dev config:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"models"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Local AI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ollama"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"qwen2.5-coder:7b"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now VS Code can use your local model for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code generation&lt;/li&gt;
&lt;li&gt;Refactoring&lt;/li&gt;
&lt;li&gt;Debugging&lt;/li&gt;
&lt;li&gt;Chat&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: Open Chat UI in Browser
&lt;/h2&gt;

&lt;p&gt;You can also use a ChatGPT-like interface locally.&lt;/p&gt;

&lt;p&gt;Install Open WebUI using Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-p&lt;/span&gt; 3000:8080 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--add-host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;host.docker.internal:host-gateway &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-v&lt;/span&gt; open-webui:/app/backend/data &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; open-webui &lt;span class="se"&gt;\&lt;/span&gt;
ghcr.io/open-webui/open-webui:main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have your own private AI chat app.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recommended Models
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Qwen2.5 Coder&lt;/td&gt;
&lt;td&gt;Coding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek Coder&lt;/td&gt;
&lt;td&gt;Refactoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama 3&lt;/td&gt;
&lt;td&gt;General AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phi&lt;/td&gt;
&lt;td&gt;Low-end laptops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mistral&lt;/td&gt;
&lt;td&gt;Fast responses&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Minimum Hardware
&lt;/h2&gt;

&lt;p&gt;Basic setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;16GB RAM recommended&lt;/li&gt;
&lt;li&gt;SSD storage&lt;/li&gt;
&lt;li&gt;NVIDIA GPU helps a lot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CPU-only works too, but slower.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Developers Like Local AI
&lt;/h2&gt;

&lt;p&gt;Main reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No monthly API bills&lt;/li&gt;
&lt;li&gt;More privacy&lt;/li&gt;
&lt;li&gt;Works offline&lt;/li&gt;
&lt;li&gt;Full control&lt;/li&gt;
&lt;li&gt;Easy experimentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For daily coding workflows, local LLMs are becoming surprisingly useful.&lt;/p&gt;

&lt;p&gt;Cloud models are still stronger for advanced reasoning, but local AI is now good enough for many real-world tasks.&lt;/p&gt;




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

&lt;p&gt;If you are spending too much on AI APIs, this is probably the easiest way to reduce costs.&lt;/p&gt;

&lt;p&gt;Start simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Ollama&lt;/li&gt;
&lt;li&gt;Pull one coding model&lt;/li&gt;
&lt;li&gt;Connect it to VS Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That alone can replace a large percentage of your daily AI usage.&lt;/p&gt;

&lt;p&gt;Useful links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openwebui.com" rel="noopener noreferrer"&gt;Open WebUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://continue.dev" rel="noopener noreferrer"&gt;Continue.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>tutorial</category>
      <category>learning</category>
    </item>
    <item>
      <title>From PR to Production: How Kubernetes Deployments Actually Work (Microservices in the Real World)</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Sun, 22 Feb 2026 16:23:51 +0000</pubDate>
      <link>https://dev.to/speaklouder/from-pr-to-production-how-kubernetes-deployments-actually-work-microservices-in-the-real-world-1cfb</link>
      <guid>https://dev.to/speaklouder/from-pr-to-production-how-kubernetes-deployments-actually-work-microservices-in-the-real-world-1cfb</guid>
      <description>&lt;p&gt;Most developers know how to write code.&lt;/p&gt;

&lt;p&gt;Fewer understand what actually happens after clicking &lt;strong&gt;“&lt;a href="https://nileshblog.tech/from-code-to-kubernetes-production-deployment-guide/" rel="noopener noreferrer"&gt;Merge Pull Request&lt;/a&gt;.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And almost nobody truly understands what Kubernetes is doing during a &lt;a href="https://nileshblog.tech/from-code-to-kubernetes-production-deployment-guide/" rel="noopener noreferrer"&gt;production deployment&lt;/a&gt; — until something breaks.&lt;/p&gt;

&lt;p&gt;This post is a practical walkthrough of how code moves from PR → CI/CD → Helm → Kubernetes → Production, especially in a microservices setup.&lt;/p&gt;

&lt;p&gt;If you’ve ever shipped something that worked locally but behaved differently in production, this is for you.&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%2Fohwndngd7zq2uujaumk6.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%2Fohwndngd7zq2uujaumk6.png" alt="Pr to Prod" width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  First: Kubernetes Doesn’t “Deploy” Your Code
&lt;/h2&gt;

&lt;p&gt;This mental model changes everything.&lt;/p&gt;

&lt;p&gt;Kubernetes doesn’t deploy applications the way we think about deployments.&lt;/p&gt;

&lt;p&gt;It maintains &lt;strong&gt;desired state&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You declare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“I want 3 replicas.”&lt;/li&gt;
&lt;li&gt;“I want image &lt;code&gt;order-service:1.4.2&lt;/code&gt;.”&lt;/li&gt;
&lt;li&gt;“I want these resource limits.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kubernetes continuously checks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does current state match desired state?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If not, it fixes it.&lt;/p&gt;

&lt;p&gt;That’s the entire system.&lt;/p&gt;

&lt;p&gt;Everything else — rolling updates, restarts, scaling — is just reconciliation.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Happens After You Merge a PR
&lt;/h2&gt;

&lt;p&gt;Let’s break this down in a real production workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — PR is merged
&lt;/h3&gt;

&lt;p&gt;You merge code into &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;develop&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No one logs into the cluster.&lt;/p&gt;

&lt;p&gt;No one runs &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — CI/CD pipeline runs
&lt;/h3&gt;

&lt;p&gt;The pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs tests (fail fast)&lt;/li&gt;
&lt;li&gt;Builds a Docker image&lt;/li&gt;
&lt;li&gt;Tags it (usually with commit SHA)&lt;/li&gt;
&lt;li&gt;Pushes it to a container registry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example image tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;order-service:1.4.2-a8f3d21
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One-line rule: Never use &lt;code&gt;latest&lt;/code&gt; in production.&lt;/p&gt;

&lt;p&gt;You want immutable, traceable builds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Deployment is triggered
&lt;/h3&gt;

&lt;p&gt;Two common approaches:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A – CI runs Helm directly&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm upgrade order-service &lt;span class="nt"&gt;--set&lt;/span&gt; image.tag&lt;span class="o"&gt;=&lt;/span&gt;1.4.2-a8f3d21
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This updates the Kubernetes Deployment spec.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B – GitOps (ArgoCD / Flux)&lt;/strong&gt;&lt;br&gt;
CI updates a config repo → GitOps controller detects change → syncs cluster.&lt;/p&gt;

&lt;p&gt;Either way, Kubernetes receives an updated Deployment object.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Kubernetes Actually Does Next
&lt;/h2&gt;

&lt;p&gt;This is where things get interesting.&lt;/p&gt;

&lt;p&gt;If the image tag changed inside:&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="s"&gt;.spec.template&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creates a new ReplicaSet&lt;/li&gt;
&lt;li&gt;Starts new pods with the new image&lt;/li&gt;
&lt;li&gt;Waits for readiness probe to succeed&lt;/li&gt;
&lt;li&gt;Gradually terminates old pods&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a rolling update.&lt;/p&gt;

&lt;p&gt;No downtime if configured correctly.&lt;/p&gt;

&lt;p&gt;No Helm magic.&lt;/p&gt;

&lt;p&gt;Just the Deployment controller doing its job.&lt;/p&gt;




&lt;h2&gt;
  
  
  Important: What Actually Triggers a Rollout
&lt;/h2&gt;

&lt;p&gt;Only changes inside &lt;code&gt;.spec.template&lt;/code&gt; trigger new ReplicaSets.&lt;/p&gt;

&lt;p&gt;Examples that trigger rollout:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image change&lt;/li&gt;
&lt;li&gt;Environment variable change&lt;/li&gt;
&lt;li&gt;Resource limit change&lt;/li&gt;
&lt;li&gt;Container command change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples that do NOT:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changing replica count (only scales)&lt;/li&gt;
&lt;li&gt;Updating a Service&lt;/li&gt;
&lt;li&gt;Editing comments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding this prevents confusion in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  Small System vs Microservices: What Changes?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Small System (Single Service)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;One Deployment&lt;/li&gt;
&lt;li&gt;One Service&lt;/li&gt;
&lt;li&gt;One Helm chart&lt;/li&gt;
&lt;li&gt;One pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple mental model.&lt;br&gt;
Easier debugging.&lt;br&gt;
Larger blast radius.&lt;/p&gt;

&lt;h3&gt;
  
  
  Microservices (Real World)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;auth-service&lt;/li&gt;
&lt;li&gt;order-service&lt;/li&gt;
&lt;li&gt;payment-service&lt;/li&gt;
&lt;li&gt;gateway&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Has its own Deployment&lt;/li&gt;
&lt;li&gt;Has its own Helm release&lt;/li&gt;
&lt;li&gt;Scales independently&lt;/li&gt;
&lt;li&gt;Deploys independently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When &lt;code&gt;order-service&lt;/code&gt; updates, only that Deployment rolls.&lt;/p&gt;

&lt;p&gt;Other services remain untouched.&lt;/p&gt;

&lt;p&gt;This isolation is the real advantage of microservices.&lt;/p&gt;

&lt;p&gt;But it comes with operational complexity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Production Mistakes I’ve Seen
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Memory limit reduced “just a little”
&lt;/h3&gt;

&lt;p&gt;Pods started OOM-killing under load during rollout.&lt;br&gt;
Traffic dropped.&lt;br&gt;
Rollback saved the night.&lt;/p&gt;

&lt;p&gt;Lesson: Resource changes are real deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. ConfigMap updated but pods didn’t restart
&lt;/h3&gt;

&lt;p&gt;ConfigMap changes do not restart pods automatically.&lt;br&gt;
You must trigger rollout manually or use checksum annotations.&lt;/p&gt;

&lt;p&gt;Lesson: Not everything behaves how you expect.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Using &lt;code&gt;latest&lt;/code&gt; tag
&lt;/h3&gt;

&lt;p&gt;Rollback becomes unpredictable.&lt;br&gt;
You lose traceability.&lt;/p&gt;

&lt;p&gt;Lesson: Immutable image tags are non-negotiable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Awareness in Deployment
&lt;/h2&gt;

&lt;p&gt;Things that matter more than people admit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No cluster-admin access for developers&lt;/li&gt;
&lt;li&gt;Proper RBAC&lt;/li&gt;
&lt;li&gt;Secrets stored securely (not in plain values.yaml)&lt;/li&gt;
&lt;li&gt;Resource limits on every container&lt;/li&gt;
&lt;li&gt;Liveness and readiness probes configured&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A deployment is also a security event.&lt;/p&gt;

&lt;p&gt;Treat it that way.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Engineering Mindset
&lt;/h2&gt;

&lt;p&gt;Don’t think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How do I deploy?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“What changed in &lt;code&gt;.spec.template&lt;/code&gt;?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you understand that, you understand Kubernetes deployments.&lt;/p&gt;

&lt;p&gt;Helm just renders YAML.&lt;/p&gt;

&lt;p&gt;CI just builds images.&lt;/p&gt;

&lt;p&gt;Kubernetes enforces desired state.&lt;/p&gt;

&lt;p&gt;That’s the real system.&lt;/p&gt;




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

&lt;p&gt;Kubernetes deployments feel complex until you understand the reconciliation loop.&lt;/p&gt;

&lt;p&gt;Once you do, they become predictable.&lt;/p&gt;

&lt;p&gt;And predictability is what keeps production stable.&lt;/p&gt;

&lt;p&gt;If you want a deeper breakdown with diagrams, failure scenarios, and production war stories, I’ve written the full long-form version here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://nileshblog.tech/from-code-to-kubernetes-production-deployment-guide/" rel="noopener noreferrer"&gt;https://nileshblog.tech/from-code-to-kubernetes-production-deployment-guide/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>productivity</category>
      <category>software</category>
      <category>git</category>
    </item>
    <item>
      <title>Why Your Node.js App Is Fast Locally but Slow in Production</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Wed, 18 Feb 2026 21:18:00 +0000</pubDate>
      <link>https://dev.to/speaklouder/why-your-nodejs-app-is-fast-locally-but-slow-in-production-2j1k</link>
      <guid>https://dev.to/speaklouder/why-your-nodejs-app-is-fast-locally-but-slow-in-production-2j1k</guid>
      <description>&lt;p&gt;If you’ve built a Node.js app, you’ve probably experienced this exact moment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“It’s blazing fast on my laptop… why is it crawling in production?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This isn’t bad luck. It’s a pattern. I’ve seen it across startups, scale-ups, and even mature systems. The gap between &lt;strong&gt;&lt;a href="https://nileshblog.tech/nodejs-run-fast-locally-slow-in-production/" rel="noopener noreferrer"&gt;local performance&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://nileshblog.tech/nodejs-run-fast-locally-slow-in-production/" rel="noopener noreferrer"&gt;production performance&lt;/a&gt;&lt;/strong&gt; exists because production is a completely different environment — more users, more network hops, more failure modes, and far fewer shortcuts.&lt;/p&gt;

&lt;p&gt;Let’s break down the real reasons this happens and what actually fixes it.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Your Local Machine Is Lying to You
&lt;/h2&gt;

&lt;p&gt;Locally, everything is optimized in your favor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requests come from &lt;code&gt;localhost&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Database runs on the same machine&lt;/li&gt;
&lt;li&gt;No real network latency&lt;/li&gt;
&lt;li&gt;Almost zero concurrency&lt;/li&gt;
&lt;li&gt;Warm caches&lt;/li&gt;
&lt;li&gt;No security layers slowing things down&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Production doesn’t have that luxury.&lt;/p&gt;

&lt;p&gt;In production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every request crosses networks&lt;/li&gt;
&lt;li&gt;Databases are remote&lt;/li&gt;
&lt;li&gt;TLS is enabled&lt;/li&gt;
&lt;li&gt;Load balancers exist&lt;/li&gt;
&lt;li&gt;Multiple users hit the same resources at once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your app isn’t slower. &lt;strong&gt;Reality is heavier.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Database Latency Is the Silent Killer
&lt;/h2&gt;

&lt;p&gt;Locally, a database query might take 2–5 ms.&lt;br&gt;
In production, that same query can take 50–200 ms.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network round trips&lt;/li&gt;
&lt;li&gt;Cold caches&lt;/li&gt;
&lt;li&gt;Larger datasets&lt;/li&gt;
&lt;li&gt;Missing indexes&lt;/li&gt;
&lt;li&gt;Shared database load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A classic example:&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;await&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feels instant locally with 100 rows.&lt;br&gt;
In production with millions of records and no index? It’s a time bomb.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Add proper indexes&lt;/li&gt;
&lt;li&gt;Log slow queries&lt;/li&gt;
&lt;li&gt;Never assume “simple queries” are cheap&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  3. Connection Pooling Misconfigurations
&lt;/h2&gt;

&lt;p&gt;One of the most common Node.js production issues.&lt;/p&gt;

&lt;p&gt;Locally, you might run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 Node process&lt;/li&gt;
&lt;li&gt;1 database connection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple Node processes&lt;/li&gt;
&lt;li&gt;Each opens its own DB connections&lt;/li&gt;
&lt;li&gt;Database connection limit gets exhausted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Symptoms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Random slowness&lt;/li&gt;
&lt;li&gt;Timeouts&lt;/li&gt;
&lt;li&gt;Requests hanging without errors&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Configure connection pools explicitly&lt;/li&gt;
&lt;li&gt;Align pool size with DB limits&lt;/li&gt;
&lt;li&gt;Monitor active connections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don’t control this, your app collapses under load.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Blocking the Event Loop (Without Realizing It)
&lt;/h2&gt;

&lt;p&gt;Node.js is fast — until you block it.&lt;/p&gt;

&lt;p&gt;Common production-only blockers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavy JSON parsing&lt;/li&gt;
&lt;li&gt;Synchronous file operations&lt;/li&gt;
&lt;li&gt;CPU-heavy loops&lt;/li&gt;
&lt;li&gt;Poorly written logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This code looks harmless:&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="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;largePayload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under real traffic, it can freeze your server.&lt;/p&gt;

&lt;p&gt;Locally, you never notice it.&lt;br&gt;
In production, concurrency exposes it instantly.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Avoid sync operations&lt;/li&gt;
&lt;li&gt;Offload CPU work to workers&lt;/li&gt;
&lt;li&gt;Measure event loop lag&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  5. Missing Timeouts Everywhere
&lt;/h2&gt;

&lt;p&gt;Local environments forgive mistakes. Production doesn’t.&lt;/p&gt;

&lt;p&gt;Without timeouts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;External APIs hang&lt;/li&gt;
&lt;li&gt;Database calls stall&lt;/li&gt;
&lt;li&gt;Requests pile up&lt;/li&gt;
&lt;li&gt;Node keeps waiting forever&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eventually, everything slows down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;br&gt;
Always define timeouts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP clients&lt;/li&gt;
&lt;li&gt;Database queries&lt;/li&gt;
&lt;li&gt;Internal service calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Timeouts are not pessimism — they are survival.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Logging Becomes a Performance Problem
&lt;/h2&gt;

&lt;p&gt;In development, logging is cheap.&lt;br&gt;
In production, logging can destroy performance.&lt;/p&gt;

&lt;p&gt;Reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Synchronous log writes&lt;/li&gt;
&lt;li&gt;Console logging under high load&lt;/li&gt;
&lt;li&gt;Log aggregation delays&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This line can be surprisingly expensive:&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="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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiply it by thousands of requests per second.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Use async loggers&lt;/li&gt;
&lt;li&gt;Reduce log volume&lt;/li&gt;
&lt;li&gt;Never log large payloads by default&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7. Scaling Without Understanding Throughput
&lt;/h2&gt;

&lt;p&gt;Adding more servers doesn’t always help.&lt;/p&gt;

&lt;p&gt;If your bottleneck is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A single database&lt;/li&gt;
&lt;li&gt;A shared cache&lt;/li&gt;
&lt;li&gt;A rate-limited API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Horizontal scaling just amplifies the problem.&lt;/p&gt;

&lt;p&gt;This is why apps feel &lt;em&gt;slower&lt;/em&gt; after scaling.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Identify the real bottleneck&lt;/li&gt;
&lt;li&gt;Scale databases and caches intentionally&lt;/li&gt;
&lt;li&gt;Add backpressure and rate limits&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  8. You’re Not Testing Production-Like Load
&lt;/h2&gt;

&lt;p&gt;Most teams test functionality, not behavior under stress.&lt;/p&gt;

&lt;p&gt;Local testing usually means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One request at a time&lt;/li&gt;
&lt;li&gt;Clean startup state&lt;/li&gt;
&lt;li&gt;Happy paths only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Production means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traffic spikes&lt;/li&gt;
&lt;li&gt;Slow dependencies&lt;/li&gt;
&lt;li&gt;Partial failures&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Load test before release&lt;/li&gt;
&lt;li&gt;Test with realistic data sizes&lt;/li&gt;
&lt;li&gt;Simulate failures, not just success&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;&lt;a href="https://nileshblog.tech/nodejs-run-fast-locally-slow-in-production/" rel="noopener noreferrer"&gt;Your Node.js app isn’t “slow in production.”&lt;/a&gt;&lt;br&gt;
It’s &lt;strong&gt;honest in production&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Local environments hide latency, concurrency, and failure. Production exposes them all at once.&lt;/p&gt;

&lt;p&gt;If you want consistent performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Respect the network&lt;/li&gt;
&lt;li&gt;Measure everything&lt;/li&gt;
&lt;li&gt;Design for concurrency&lt;/li&gt;
&lt;li&gt;Expect things to fail&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fast local performance is a confidence boost.&lt;br&gt;
Fast production performance is an engineering achievement.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Idempotency: The Concept Everyone Mentions but Few Implement Correctly</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Mon, 16 Feb 2026 20:06:00 +0000</pubDate>
      <link>https://dev.to/speaklouder/idempotency-the-concept-everyone-mentions-but-few-implement-correctly-2pbc</link>
      <guid>https://dev.to/speaklouder/idempotency-the-concept-everyone-mentions-but-few-implement-correctly-2pbc</guid>
      <description>&lt;p&gt;&lt;a href="https://nileshblog.tech/idempotency-explained-designing-retry-safe-apis/" rel="noopener noreferrer"&gt;Idempotency&lt;/a&gt; is one of those words that shows up everywhere: system design interviews, API docs, architecture diagrams, and postmortems. Everyone nods when it’s mentioned. Few teams actually implement it correctly.&lt;/p&gt;

&lt;p&gt;I’ve seen idempotency “implemented” with comments, flags, retries, or blind faith in the network. And I’ve also seen real production outages that could have been avoided with a proper idempotency strategy.&lt;/p&gt;

&lt;p&gt;This article is about what idempotency &lt;em&gt;really&lt;/em&gt; means in practice, where it breaks down, and how to implement it in real systems—not slides.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Idempotency Actually Means (Beyond the Definition)
&lt;/h2&gt;

&lt;p&gt;The textbook definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An operation is idempotent if performing it multiple times has the same effect as performing it once.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s technically correct but operationally incomplete.&lt;/p&gt;

&lt;p&gt;In real systems, &lt;a href="https://nileshblog.tech/idempotency-explained-designing-retry-safe-apis/" rel="noopener noreferrer"&gt;idempotency&lt;/a&gt; is about &lt;strong&gt;protecting your system from duplicates caused by retries, timeouts, race conditions, and partial failures&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your API client retries because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the network dropped,&lt;/li&gt;
&lt;li&gt;the load balancer timed out,&lt;/li&gt;
&lt;li&gt;the user double-clicked,&lt;/li&gt;
&lt;li&gt;a worker crashed mid-request,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;your system should not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;charge twice,&lt;/li&gt;
&lt;li&gt;create duplicate records,&lt;/li&gt;
&lt;li&gt;send duplicate emails,&lt;/li&gt;
&lt;li&gt;corrupt state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s the real problem idempotency solves.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Idempotency Matters (and Where It Doesn’t)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Common places it &lt;strong&gt;does&lt;/strong&gt; matter
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Payments and billing&lt;/li&gt;
&lt;li&gt;Order creation&lt;/li&gt;
&lt;li&gt;Inventory reservations&lt;/li&gt;
&lt;li&gt;Webhooks&lt;/li&gt;
&lt;li&gt;Background jobs and queues&lt;/li&gt;
&lt;li&gt;External API integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Places it usually &lt;strong&gt;doesn’t&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pure reads (&lt;code&gt;GET&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Analytics counters (if approximate is acceptable)&lt;/li&gt;
&lt;li&gt;Fire-and-forget logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If an operation changes money, state, or inventory, idempotency is not optional.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Biggest Misconception: “POST Is Not Idempotent”
&lt;/h2&gt;

&lt;p&gt;You’ll often hear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GET is idempotent, POST is not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s an HTTP convention, not a system guarantee.&lt;/p&gt;

&lt;p&gt;You can (and often must) make POST requests idempotent at the application level. Payments APIs do this all the time.&lt;/p&gt;

&lt;p&gt;The HTTP method does not save you. Your backend design does.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Naive (and Wrong) Implementations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. “We Just Retry”
&lt;/h3&gt;

&lt;p&gt;Retries without idempotency &lt;strong&gt;multiply bugs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your payment service retries blindly and your backend creates a new record each time, you’ve just automated duplication.&lt;/p&gt;

&lt;p&gt;Retries are only safe &lt;em&gt;after&lt;/em&gt; idempotency is enforced.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. “We Check If It Exists”
&lt;/h3&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fails under concurrency.&lt;/p&gt;

&lt;p&gt;Two requests arrive at the same time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;both see “not exists”&lt;/li&gt;
&lt;li&gt;both insert&lt;/li&gt;
&lt;li&gt;congratulations, you have duplicates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a race condition, not idempotency.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. “We Use a Boolean Flag”
&lt;/h3&gt;

&lt;p&gt;Flags like &lt;code&gt;is_processed = true&lt;/code&gt; work only if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the operation is atomic&lt;/li&gt;
&lt;li&gt;the write is guaranteed to happen once&lt;/li&gt;
&lt;li&gt;there’s no partial failure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In distributed systems, those assumptions rarely hold.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Correct Mental Model
&lt;/h2&gt;

&lt;p&gt;Idempotency is about &lt;strong&gt;deduplicating intent&lt;/strong&gt;, not requests.&lt;/p&gt;

&lt;p&gt;You don’t care how many times a request arrives.&lt;br&gt;
You care that the &lt;em&gt;same logical action&lt;/em&gt; is processed once.&lt;/p&gt;

&lt;p&gt;That’s why idempotency keys exist.&lt;/p&gt;


&lt;h2&gt;
  
  
  Idempotency Keys: The Foundation
&lt;/h2&gt;

&lt;p&gt;An idempotency key is a &lt;strong&gt;client-generated unique identifier&lt;/strong&gt; for a logical operation.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Idempotency-Key: 7f3c9c2e-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same logical action → same key&lt;/li&gt;
&lt;li&gt;Different action → different key&lt;/li&gt;
&lt;li&gt;Client must retry with the same key&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A Minimal, Correct Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Store the key
&lt;/h3&gt;

&lt;p&gt;Create a table or cache entry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;idempotency_key
request_hash
response
status
created_at
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Enforce uniqueness
&lt;/h3&gt;

&lt;p&gt;The key must be unique at the database or cache level.&lt;br&gt;
This prevents race conditions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: On request
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Check if the key exists&lt;/li&gt;
&lt;li&gt;If yes:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;return the stored response&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If no:&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;process the request&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;store the response&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;return it&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retries are safe&lt;/li&gt;
&lt;li&gt;duplicates are impossible&lt;/li&gt;
&lt;li&gt;responses are consistent&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Handling Partial Failures (The Hard Part)
&lt;/h2&gt;

&lt;p&gt;What if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the operation succeeds,&lt;/li&gt;
&lt;li&gt;but the response fails to return?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without idempotency, the client retries and triggers a duplicate.&lt;/p&gt;

&lt;p&gt;With idempotency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the retry hits the same key&lt;/li&gt;
&lt;li&gt;you return the stored success response&lt;/li&gt;
&lt;li&gt;the system remains consistent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where most “implementations” fail—they don’t store the response.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Example: Payments
&lt;/h2&gt;

&lt;p&gt;Payment providers treat idempotency as mandatory.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Networks are unreliable&lt;/li&gt;
&lt;li&gt;Clients retry aggressively&lt;/li&gt;
&lt;li&gt;Money cannot be duplicated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A payment API without idempotency is reckless.&lt;/p&gt;

&lt;p&gt;The same logic applies to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;order creation&lt;/li&gt;
&lt;li&gt;inventory deduction&lt;/li&gt;
&lt;li&gt;subscription changes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Performance and Storage Trade-offs
&lt;/h2&gt;

&lt;p&gt;Idempotency isn’t free.&lt;/p&gt;

&lt;p&gt;Costs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;extra storage&lt;/li&gt;
&lt;li&gt;lookup overhead&lt;/li&gt;
&lt;li&gt;TTL management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Optimizations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Redis with TTL for short-lived operations&lt;/li&gt;
&lt;li&gt;Use DB for long-lived financial records&lt;/li&gt;
&lt;li&gt;Expire keys safely (not too early)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Never trade correctness for &lt;a href="https://nileshblog.tech/idempotency-explained-designing-retry-safe-apis/" rel="noopener noreferrer"&gt;micro-optimizations&lt;/a&gt; here.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Treat idempotency keys as untrusted input&lt;/li&gt;
&lt;li&gt;Scope keys per user or client&lt;/li&gt;
&lt;li&gt;Avoid global collisions&lt;/li&gt;
&lt;li&gt;Don’t allow attackers to replay sensitive actions indefinitely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Idempotency improves safety, but careless design can introduce replay risks.&lt;/p&gt;




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

&lt;p&gt;Idempotency is not a buzzword. It’s a discipline.&lt;/p&gt;

&lt;p&gt;If your system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retries requests,&lt;/li&gt;
&lt;li&gt;talks over a network,&lt;/li&gt;
&lt;li&gt;processes money or state,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;then idempotency is part of your correctness model, not an “extra feature.”&lt;/p&gt;

&lt;p&gt;Most bugs blamed on “network issues” are actually idempotency failures.&lt;/p&gt;

&lt;p&gt;Implement it once. Implement it right. Your future self—and your on-call rotation—will thank you.&lt;/p&gt;

</description>
      <category>software</category>
      <category>systemdesign</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Redis Is Not a Database (Until You Treat It Like One)</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Fri, 13 Feb 2026 19:09:28 +0000</pubDate>
      <link>https://dev.to/speaklouder/redis-is-not-a-database-until-you-treat-it-like-one-11j8</link>
      <guid>https://dev.to/speaklouder/redis-is-not-a-database-until-you-treat-it-like-one-11j8</guid>
      <description>&lt;p&gt;Redis is one of those tools almost every backend engineer has used—and many have misused.&lt;/p&gt;

&lt;p&gt;It starts simple: &lt;em&gt;“Let’s just cache it.”&lt;/em&gt;&lt;br&gt;
Then Redis works so well that it slowly becomes &lt;em&gt;the system&lt;/em&gt;.&lt;br&gt;
Before you know it, business logic depends on Redis keys, not your primary database.&lt;/p&gt;

&lt;p&gt;That’s where things usually go wrong.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nileshblog.tech/redis-is-not-a-database-until-you-treat-it-like-one/" rel="noopener noreferrer"&gt;Redis &lt;/a&gt;is &lt;strong&gt;not&lt;/strong&gt; a database by default.&lt;br&gt;
But with the right discipline, configuration, and mindset—it &lt;em&gt;can&lt;/em&gt; behave like one.&lt;/p&gt;

&lt;p&gt;This article is about drawing that line clearly, from real production experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why &lt;a href="https://nileshblog.tech/redis-is-not-a-database-until-you-treat-it-like-one/" rel="noopener noreferrer"&gt;Redis Is Not a Database&lt;/a&gt; (By Default)
&lt;/h2&gt;

&lt;p&gt;Redis was designed for &lt;strong&gt;speed first&lt;/strong&gt;, durability second.&lt;/p&gt;

&lt;p&gt;Out of the box, Redis optimizes for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In-memory access&lt;/li&gt;
&lt;li&gt;Low latency&lt;/li&gt;
&lt;li&gt;Simple data structures&lt;/li&gt;
&lt;li&gt;Fast eviction and expiration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What it does &lt;em&gt;not&lt;/em&gt; guarantee by default:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strong durability&lt;/li&gt;
&lt;li&gt;Crash-safe persistence&lt;/li&gt;
&lt;li&gt;Complex querying&lt;/li&gt;
&lt;li&gt;Schema enforcement&lt;/li&gt;
&lt;li&gt;Long-term data retention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you treat Redis like PostgreSQL without adjusting anything, you’re setting yourself up for silent data loss.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Common Trap: “It’s Just Temporary”
&lt;/h2&gt;

&lt;p&gt;Most Redis usage begins as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Session storage&lt;/li&gt;
&lt;li&gt;Cache layer&lt;/li&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Feature flags&lt;/li&gt;
&lt;li&gt;Counters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All fine use cases.&lt;/p&gt;

&lt;p&gt;The problem appears when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redis becomes the &lt;strong&gt;only&lt;/strong&gt; source of truth&lt;/li&gt;
&lt;li&gt;Writes happen &lt;strong&gt;only&lt;/strong&gt; to Redis&lt;/li&gt;
&lt;li&gt;The database becomes “optional”&lt;/li&gt;
&lt;li&gt;TTLs are misunderstood or ignored&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point, Redis is no longer a cache.&lt;br&gt;
It’s an &lt;em&gt;undeclared database&lt;/em&gt;—and an unsafe one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Persistence: The First Reality Check
&lt;/h2&gt;

&lt;p&gt;Redis persistence is &lt;strong&gt;opt-in&lt;/strong&gt; and &lt;strong&gt;configurable&lt;/strong&gt;, not guaranteed.&lt;/p&gt;

&lt;h3&gt;
  
  
  RDB (Snapshots)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Periodic point-in-time dumps&lt;/li&gt;
&lt;li&gt;Fast restarts&lt;/li&gt;
&lt;li&gt;Risk of losing recent writes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One-line explanation: &lt;em&gt;Good for caches, dangerous for critical writes.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AOF (Append-Only File)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Logs every write operation&lt;/li&gt;
&lt;li&gt;Better durability&lt;/li&gt;
&lt;li&gt;Slower writes and larger disk usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One-line explanation: &lt;em&gt;Closer to database behavior, but still not perfect.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AOF + RDB
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Common production setup&lt;/li&gt;
&lt;li&gt;Balances performance and recovery time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One-line explanation: &lt;em&gt;Still requires testing, monitoring, and discipline.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you haven’t tested:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Power loss&lt;/li&gt;
&lt;li&gt;Container restarts&lt;/li&gt;
&lt;li&gt;Disk-full scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t know how durable your Redis really is.&lt;/p&gt;




&lt;h2&gt;
  
  
  Redis Without Backups Is a Risk, Not a System
&lt;/h2&gt;

&lt;p&gt;In real systems, I’ve seen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entire user sessions wiped during deploys&lt;/li&gt;
&lt;li&gt;Order states lost after node crashes&lt;/li&gt;
&lt;li&gt;Feature flags reset during failover&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All because Redis persistence was assumed, not verified.&lt;/p&gt;

&lt;p&gt;If Redis contains anything you cannot afford to lose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable persistence explicitly&lt;/li&gt;
&lt;li&gt;Back it up externally&lt;/li&gt;
&lt;li&gt;Monitor persistence failures&lt;/li&gt;
&lt;li&gt;Test restores regularly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Databases are boring because they survive disasters.&lt;br&gt;
Redis is fast because it assumes you know what you’re doing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Concurrency: Redis Is Atomic, Not Magical
&lt;/h2&gt;

&lt;p&gt;Redis commands are atomic—but your system logic may not be.&lt;/p&gt;

&lt;p&gt;Problems appear when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple keys must change together&lt;/li&gt;
&lt;li&gt;Business rules span multiple operations&lt;/li&gt;
&lt;li&gt;Failures happen mid-flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solutions Redis gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transactions (&lt;code&gt;MULTI/EXEC&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Lua scripts&lt;/li&gt;
&lt;li&gt;Single-threaded execution model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One-line explanation: &lt;em&gt;You must design atomicity explicitly, not assume it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you’re modeling workflows, reservations, or financial state—Lua scripting is not optional.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Redis &lt;em&gt;Can&lt;/em&gt; Act Like a Database
&lt;/h2&gt;

&lt;p&gt;Redis starts behaving like a database only when you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable and test persistence&lt;/li&gt;
&lt;li&gt;Design for crash recovery&lt;/li&gt;
&lt;li&gt;Use Lua for invariants&lt;/li&gt;
&lt;li&gt;Avoid TTLs for critical data&lt;/li&gt;
&lt;li&gt;Replicate and monitor aggressively&lt;/li&gt;
&lt;li&gt;Treat memory limits seriously&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, Redis stops being “just a cache” and becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A fast primary store&lt;/li&gt;
&lt;li&gt;A coordination layer&lt;/li&gt;
&lt;li&gt;A real-time state engine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But note the cost: &lt;strong&gt;engineering effort&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Small Systems vs Large Systems
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Small Systems
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Redis as cache only&lt;/li&gt;
&lt;li&gt;Database as source of truth&lt;/li&gt;
&lt;li&gt;Occasional Redis loss is acceptable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the safest setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Large Systems
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Redis used for locks, counters, queues, reservations&lt;/li&gt;
&lt;li&gt;Database writes are async&lt;/li&gt;
&lt;li&gt;Redis outages cause business impact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here, Redis must be engineered like a database—or removed from the critical path.&lt;/p&gt;

&lt;p&gt;There is no middle ground.&lt;/p&gt;




&lt;p&gt;Common issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unauthenticated Redis exposed internally&lt;/li&gt;
&lt;li&gt;Accidental &lt;code&gt;FLUSHALL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Memory exhaustion causing eviction&lt;/li&gt;
&lt;li&gt;Replica lag causing stale reads&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Mental Model That Actually Works
&lt;/h2&gt;

&lt;p&gt;Use this rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If Redis data disappears, can my system recover automatically?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yes&lt;/strong&gt; → Redis is a cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No&lt;/strong&gt; → Redis is a database, whether you admit it or not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once Redis becomes unrecoverable state, you must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Engineer it like a database&lt;/li&gt;
&lt;li&gt;Or redesign the system&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Redis is an incredible tool—but it’s honest about what it is.&lt;/p&gt;

&lt;p&gt;It will not stop you from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Losing data&lt;/li&gt;
&lt;li&gt;Overloading memory&lt;/li&gt;
&lt;li&gt;Designing unsafe flows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That responsibility is yours.&lt;/p&gt;

&lt;p&gt;Treat Redis lightly, and it will betray you quietly.&lt;br&gt;
Treat it like a database, and it will reward you with speed most systems can only dream of.&lt;/p&gt;

&lt;p&gt;The danger isn’t Redis.&lt;br&gt;
The danger is pretending it’s something it never promised to be.&lt;/p&gt;

</description>
      <category>redis</category>
      <category>software</category>
      <category>discuss</category>
      <category>database</category>
    </item>
    <item>
      <title>20+ Git Commands Every Software Engineer Should Actually Know</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Sat, 31 Jan 2026 04:07:31 +0000</pubDate>
      <link>https://dev.to/speaklouder/20-git-commands-every-software-engineer-should-actually-know-1gnf</link>
      <guid>https://dev.to/speaklouder/20-git-commands-every-software-engineer-should-actually-know-1gnf</guid>
      <description>&lt;p&gt;Most engineers use Git every day—but only a handful of commands.&lt;br&gt;
That’s fine… until something goes wrong.&lt;/p&gt;

&lt;p&gt;A bad merge.&lt;br&gt;
A wrong commit.&lt;br&gt;
A force-push panic.&lt;/p&gt;

&lt;p&gt;This list covers &lt;strong&gt;&lt;a href="https://nileshblog.tech/20-git-commands-every-software-engineer-should-know/" rel="noopener noreferrer"&gt;20+ Git commands&lt;/a&gt;&lt;/strong&gt; you’ll actually use in real projects, with &lt;strong&gt;one-line explanations&lt;/strong&gt; so you know &lt;em&gt;what they do and when to use them&lt;/em&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Core &lt;a href="https://nileshblog.tech/20-git-commands-every-software-engineer-should-know/" rel="noopener noreferrer"&gt;Git Commands&lt;/a&gt; Basics
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. &lt;code&gt;git init&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Creates a new Git repository in the current directory.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. &lt;code&gt;git clone&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Downloads an existing remote repository to your local machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &amp;lt;repo-url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. &lt;code&gt;git status&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Shows the current state of files (modified, staged, untracked).&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. &lt;code&gt;git add&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Stages files so they’re included in the next commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git add file.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. &lt;code&gt;git commit&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Saves staged changes as a snapshot with a message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"message"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. &lt;code&gt;git push&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Uploads local commits to the remote repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  7. &lt;code&gt;git pull&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Fetches remote changes and merges them into your branch.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Branching &amp;amp; Navigation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  8. &lt;code&gt;git branch&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Lists branches or creates a new branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git branch
git branch feature-x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  9. &lt;code&gt;git checkout&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Switches branches or restores files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout feature-x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  10. &lt;code&gt;git switch&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A cleaner, modern way to switch branches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  11. &lt;code&gt;git merge&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Combines another branch into the current branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git merge feature-x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  12. &lt;code&gt;git log&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Shows commit history for the current branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;--graph&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Undoing Mistakes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  13. &lt;code&gt;git reset&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Moves HEAD and optionally discards commits or changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--soft&lt;/span&gt; HEAD~1
git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; HEAD~1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  14. &lt;code&gt;git revert&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Creates a new commit that safely undoes an older commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git revert &amp;lt;commit-hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  15. &lt;code&gt;git checkout -- &amp;lt;file&amp;gt;&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Discards local changes to a specific file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;--&lt;/span&gt; index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Temporary Work
&lt;/h2&gt;

&lt;h3&gt;
  
  
  16. &lt;code&gt;git stash&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Temporarily saves uncommitted changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash
git stash pop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  17. &lt;code&gt;git stash list&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Shows all saved stashes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Working With Remotes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  18. &lt;code&gt;git remote -v&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Displays configured remote repositories.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  19. &lt;code&gt;git fetch&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Downloads remote changes without merging them.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Inspecting Changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  20. &lt;code&gt;git diff&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Shows differences between files, commits, or stages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff
git diff &lt;span class="nt"&gt;--staged&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  21. &lt;code&gt;git blame&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Shows who last modified each line of a file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git blame file.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  22. &lt;code&gt;git show&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Displays detailed information about a specific commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git show &amp;lt;commit-hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Cleanup &amp;amp; Recovery
&lt;/h2&gt;

&lt;h3&gt;
  
  
  23. &lt;code&gt;git clean&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Removes untracked files from the working directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clean &lt;span class="nt"&gt;-fd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  24. &lt;code&gt;git reflog&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Shows every move of HEAD, even deleted or lost commits.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  How Senior Engineers Actually Use Git
&lt;/h2&gt;

&lt;p&gt;Senior engineers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;check &lt;code&gt;git status&lt;/code&gt; constantly,&lt;/li&gt;
&lt;li&gt;prefer &lt;code&gt;revert&lt;/code&gt; over &lt;code&gt;reset&lt;/code&gt; on shared branches,&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;fetch&lt;/code&gt; before risky merges,&lt;/li&gt;
&lt;li&gt;rely on &lt;code&gt;reflog&lt;/code&gt; when things go wrong.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Git isn’t just version control—it’s your &lt;strong&gt;safety net&lt;/strong&gt;.&lt;/p&gt;




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

&lt;p&gt;You don’t need to memorize Git.&lt;br&gt;
You need to &lt;strong&gt;understand enough to recover when things break&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Master these commands and you’ll:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;move faster,&lt;/li&gt;
&lt;li&gt;panic less,&lt;/li&gt;
&lt;li&gt;and collaborate better.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Git won’t make you a better engineer—but &lt;strong&gt;not knowing Git can absolutely make you a worse one&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>git</category>
      <category>software</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Vibe Coding vs Engineering Judgment: Where Speed Ends and Responsibility Begins</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Wed, 14 Jan 2026 14:42:57 +0000</pubDate>
      <link>https://dev.to/speaklouder/vibe-coding-vs-engineering-judgment-where-speed-ends-and-responsibility-begins-5fpn</link>
      <guid>https://dev.to/speaklouder/vibe-coding-vs-engineering-judgment-where-speed-ends-and-responsibility-begins-5fpn</guid>
      <description>&lt;p&gt;Right now, vibe coding is everywhere.&lt;/p&gt;

&lt;p&gt;You prompt an AI, stay in flow, generate code quickly, and ship something that &lt;em&gt;looks&lt;/em&gt; correct. Demos work. Tests pass. It feels productive.&lt;/p&gt;

&lt;p&gt;And then production reminds you why engineering exists.&lt;/p&gt;

&lt;p&gt;This post isn’t anti-AI. I use AI daily. But after working on real systems, handling incidents, and reviewing production code, one thing has become clear:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vibe coding accelerates output. &lt;a href="https://nileshblog.tech/vibe-coding-vs-engineering-judgment-why-speed-alone-cant-ship-reliable-software/" rel="noopener noreferrer"&gt;Engineering judgment&lt;/a&gt; protects systems.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You need both—but they solve very different problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  What People Actually Mean by Vibe Coding
&lt;/h2&gt;

&lt;p&gt;Vibe coding usually looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rapid AI-assisted code generation,&lt;/li&gt;
&lt;li&gt;minimal planning,&lt;/li&gt;
&lt;li&gt;trusting the output because “it works”,&lt;/li&gt;
&lt;li&gt;prioritizing momentum over structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s popular because it removes friction. No blank page. No syntax struggles. No context switching.&lt;/p&gt;

&lt;p&gt;For the right use cases, that’s a real advantage.&lt;/p&gt;

&lt;p&gt;The problem starts when speed becomes the goal instead of correctness.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Vibe Coding Feels So Effective
&lt;/h2&gt;

&lt;p&gt;Vibe coding works because it eliminates pain points developers hate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;staring at an empty file,&lt;/li&gt;
&lt;li&gt;boilerplate work,&lt;/li&gt;
&lt;li&gt;repetitive setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI fills gaps instantly and keeps you moving. For small scopes, this is a genuine productivity boost.&lt;/p&gt;

&lt;p&gt;But momentum without judgment doesn’t equal progress—it just means you’re moving fast in &lt;em&gt;some&lt;/em&gt; direction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Vibe Coding Works Well ✅
&lt;/h2&gt;

&lt;p&gt;Let’s be honest about where vibe coding shines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disposable Prototypes
&lt;/h3&gt;

&lt;p&gt;If the code will be thrown away—POCs, demos, experiments—vibe coding is ideal. Longevity doesn’t matter. Speed does.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hackathons &amp;amp; Side Projects
&lt;/h3&gt;

&lt;p&gt;When the goal is learning or validation, not production stability, &lt;a href="https://nileshblog.tech/vibe-coding-vs-engineering-judgment-why-speed-alone-cant-ship-reliable-software/" rel="noopener noreferrer"&gt;vibe coding&lt;/a&gt; is a net win.&lt;/p&gt;

&lt;h3&gt;
  
  
  Boilerplate &amp;amp; Scaffolding
&lt;/h3&gt;

&lt;p&gt;CRUD APIs, basic UI layouts, config setup—AI handles these well and saves real time.&lt;/p&gt;

&lt;p&gt;In all these cases, the cost of mistakes is low.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Vibe Coding Fails ❌
&lt;/h2&gt;

&lt;p&gt;This is where experience matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Large, Long-Lived Systems
&lt;/h3&gt;

&lt;p&gt;Code that must survive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple teams,&lt;/li&gt;
&lt;li&gt;refactors,&lt;/li&gt;
&lt;li&gt;scaling,&lt;/li&gt;
&lt;li&gt;years of maintenance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI-generated structure often looks clean early and becomes painful later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security-Critical Code
&lt;/h3&gt;

&lt;p&gt;Auth, permissions, payments, secrets.&lt;br&gt;
Vibe coding here is risky because insecure defaults don’t fail loudly—they fail later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complex Business Logic
&lt;/h3&gt;

&lt;p&gt;Business rules are messy and full of exceptions. AI tends to simplify them incorrectly and encode assumptions that break in edge cases.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real Mistake I Made Using Vibe Coding
&lt;/h2&gt;

&lt;p&gt;I once used AI to quickly implement a background job flow. It worked perfectly in staging. Clean retries. Nice abstractions.&lt;/p&gt;

&lt;p&gt;What I missed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retries weren’t idempotent,&lt;/li&gt;
&lt;li&gt;partial failures caused duplicate writes,&lt;/li&gt;
&lt;li&gt;logs hid the real issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It took a production incident to uncover it.&lt;/p&gt;

&lt;p&gt;The AI didn’t make the mistake.&lt;br&gt;
I did—by trusting speed over judgment.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Much Vibe Coding Is Too Much?
&lt;/h2&gt;

&lt;p&gt;A simple rule that works:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you can’t explain why the code is safe, you shouldn’t ship it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI can help write code.&lt;br&gt;
Only humans can own the consequences.&lt;/p&gt;

&lt;p&gt;Use AI as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an assistant,&lt;/li&gt;
&lt;li&gt;a drafting tool,&lt;/li&gt;
&lt;li&gt;a productivity multiplier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not as the architect or decision-maker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Risks Are the Quiet Problem
&lt;/h2&gt;

&lt;p&gt;The biggest danger of vibe coding isn’t broken code—it’s unquestioned code.&lt;/p&gt;

&lt;p&gt;Common issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hardcoded secrets “temporarily” left in place,&lt;/li&gt;
&lt;li&gt;overly permissive access checks,&lt;/li&gt;
&lt;li&gt;unsafe dependency choices,&lt;/li&gt;
&lt;li&gt;missing validation paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything looks fine until it isn’t.&lt;/p&gt;

&lt;p&gt;Security requires skepticism. AI doesn’t have that instinct.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Practices for Safe Vibe Coding
&lt;/h2&gt;

&lt;p&gt;What’s worked for me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slow down at boundaries (auth, data writes, integrations)&lt;/li&gt;
&lt;li&gt;Review AI code as if someone else wrote it&lt;/li&gt;
&lt;li&gt;Ask how it fails, not just how it works&lt;/li&gt;
&lt;li&gt;Never skip human code review&lt;/li&gt;
&lt;li&gt;Treat AI output as untrusted by default&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Speed without discipline just moves problems downstream.&lt;/p&gt;




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

&lt;p&gt;Vibe coding isn’t bad.&lt;br&gt;
Blind vibe coding is.&lt;/p&gt;

&lt;p&gt;Use vibe coding to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;explore ideas,&lt;/li&gt;
&lt;li&gt;reduce friction,&lt;/li&gt;
&lt;li&gt;move fast where risk is low.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rely on engineering judgment to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;protect users,&lt;/li&gt;
&lt;li&gt;secure systems,&lt;/li&gt;
&lt;li&gt;design for failure,&lt;/li&gt;
&lt;li&gt;own production outcomes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Speed ships features. Judgment keeps systems alive.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s the difference experience teaches you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>vibecoding</category>
      <category>software</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How Video Platforms Show Instant Hover Previews Using Sprite Sheets in Node.js</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Mon, 12 Jan 2026 15:07:48 +0000</pubDate>
      <link>https://dev.to/speaklouder/how-video-platforms-show-instant-hover-previews-using-sprite-sheets-in-nodejs-2l0l</link>
      <guid>https://dev.to/speaklouder/how-video-platforms-show-instant-hover-previews-using-sprite-sheets-in-nodejs-2l0l</guid>
      <description>&lt;p&gt;If you’ve ever hovered over a video timeline and seen preview images change instantly, you’ve already interacted with sprite sheets—even if you didn’t know what they were called.&lt;/p&gt;

&lt;p&gt;Those previews aren’t loaded one image at a time. That approach would be slow, expensive, and unreliable once traffic grows. Instead, the application loads &lt;strong&gt;one image&lt;/strong&gt; and reuses it efficiently.&lt;/p&gt;

&lt;p&gt;Sprite sheets are still one of the most practical ways to build &lt;strong&gt;fast, interactive image previews&lt;/strong&gt;, especially for video platforms, dashboards, and media-heavy applications where user interaction needs to feel instant.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real-World Example: Video Timeline Hover
&lt;/h2&gt;

&lt;p&gt;Think about how video platforms handle timeline previews.&lt;/p&gt;

&lt;p&gt;As you move your cursor across the progress bar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;preview frames update immediately,&lt;/li&gt;
&lt;li&gt;there’s no visible loading,&lt;/li&gt;
&lt;li&gt;network activity doesn’t spike.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What’s happening behind the scenes is simple and effective. The frontend loads a &lt;strong&gt;single &lt;a href="https://nileshblog.tech/sprite-sheets-in-node-js-how-video-platforms-show-fast-hover-previews-without-loading-hundreds-of-images/" rel="noopener noreferrer"&gt;sprite sheet &lt;/a&gt;image&lt;/strong&gt; ahead of time. As the user scrubs through the timeline, the UI just changes which part of that image is visible. After the initial load, the network is no longer involved.&lt;/p&gt;

&lt;p&gt;That’s why the interaction feels smooth and predictable.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Sprite Sheet Actually Is
&lt;/h2&gt;

&lt;p&gt;A sprite sheet is a &lt;strong&gt;single image that contains many smaller images arranged in a grid&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here’s an example of a real sprite sheet generated from a video, showing how multiple preview frames are packed into a single image.&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%2Fpmk9ov413yb7qfntyjnv.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%2Fpmk9ov413yb7qfntyjnv.png" alt="Sprite sheet containing video preview thumbnails generated from a video" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of loading multiple files like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;thumb_01.jpg
thumb_02.jpg
thumb_03.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the application loads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spritesheet.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend then displays only the relevant section of that image using simple position calculations. No additional image requests are required during interaction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Sprite Sheets Still Matter
&lt;/h2&gt;

&lt;p&gt;Even with HTTP/2, CDNs, and faster networks, sprite sheets solve problems that haven’t gone away:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;they drastically reduce the number of image requests,&lt;/li&gt;
&lt;li&gt;hover interactions feel instant,&lt;/li&gt;
&lt;li&gt;backend load stays predictable,&lt;/li&gt;
&lt;li&gt;caching works extremely well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For interactive previews, removing the network from the critical interaction path makes a noticeable difference in user experience.&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%2Fefjp0q6mt0g0gm1mwadh.webp" alt="Flow diagram of example sprite sheet" width="800" height="533"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Backend Responsibilities (Node.js)
&lt;/h2&gt;

&lt;p&gt;The backend should &lt;strong&gt;never&lt;/strong&gt; generate preview images on demand.&lt;/p&gt;

&lt;p&gt;In a production setup, the backend is responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generating &lt;a href="https://nileshblog.tech/sprite-sheets-in-node-js-how-video-platforms-show-fast-hover-previews-without-loading-hundreds-of-images/" rel="noopener noreferrer"&gt;sprite sheets&lt;/a&gt; asynchronously,&lt;/li&gt;
&lt;li&gt;storing them as static assets,&lt;/li&gt;
&lt;li&gt;exposing metadata that describes how the sprite sheet is structured.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sprite generation typically runs in background jobs or media pipelines, not inside API request handlers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Sprite Metadata
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"spriteUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/sprites/video_101.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"frameWidth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"frameHeight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"columns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rows"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"intervalSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&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;p&gt;This metadata is what allows the frontend to correctly calculate which frame to show at any given time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Simple Node.js Backend Example
&lt;/h2&gt;

&lt;p&gt;Here’s a minimal Express setup that exposes sprite metadata and serves the sprite image as a static asset.&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="s2"&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;sharp&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="s2"&gt;sharp&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/sprites&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sprites&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Upload video to generate the sprites sheet of that image &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;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video&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;videoPath&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;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;videoName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalname&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;name&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;thumbnailsDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`thumbnails/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;videoName&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spriteOutput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`sprites/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;videoName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.jpg`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thumbnailsDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;recursive&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;// 1. Extract frames every 2 seconds&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;extractCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    ffmpeg -i &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;videoPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; -vf fps=1/2 &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;thumbnailsDir&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/thumb_%03d.jpg
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;extractCmd&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="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;err&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Frame extraction failed:&lt;/span&gt;&lt;span class="dl"&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thumbnailsDir&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;frameWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;160&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;frameHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&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;columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&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;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;columns&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;spriteWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;frameWidth&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;columns&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;spriteHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;frameHeight&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rows&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;compositeImages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&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;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;columns&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;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;columns&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="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thumbnailsDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;frameWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;frameHeight&lt;/span&gt;
      &lt;span class="p"&gt;};&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;sharp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&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;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;spriteWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;spriteHeight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#000&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="nf"&gt;composite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compositeImages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jpeg&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spriteOutput&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;Sprite sheet created:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;spriteOutput&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Store the generated sprite sheet in object storage (e.g. S3, GCS)&lt;/span&gt;
&lt;span class="c1"&gt;// and save the sprite URL + frame metadata with the video record&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Video uploaded successfully. Sprite generation started.&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;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="s2"&gt;/api/video/:id/sprite&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="c1"&gt;//add your own logic to how to acces the new genrated image eg store in to s3 storage any where and return the url of image &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="na"&gt;spriteUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/sprites/video_101.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;frameWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;frameHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;intervalSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&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="o"&gt;=&amp;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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server running on port 3000&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;This approach scales cleanly because the backend only serves metadata and static files. The heavy work happens elsewhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frontend Handling (Plain JavaScript)
&lt;/h2&gt;

&lt;p&gt;On the frontend, the logic is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;fetch the sprite metadata,&lt;/li&gt;
&lt;li&gt;load the sprite image once,&lt;/li&gt;
&lt;li&gt;update the visible frame based on cursor position.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  HTML
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"timeline"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"preview"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&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;preview&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preview&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;timeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timeline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&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="s2"&gt;/api/video/101/sprite&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&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="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;data&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;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backgroundImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`url(&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;spriteUrl&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;frameWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;frameHeight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;intervalSeconds&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&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;timeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mousemove&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;e&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;rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;timeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&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;percent&lt;/span&gt; &lt;span class="o"&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="nx"&gt;clientX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&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;videoDuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// seconds&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hoverTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;percent&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;videoDuration&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;frameIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hoverTime&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;intervalSeconds&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;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;frameIndex&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;columns&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;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frameIndex&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backgroundPosition&lt;/span&gt; &lt;span class="o"&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;col&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;frameWidth&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px -&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;frameHeight&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&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;Once the sprite image is loaded, preview updates happen entirely on the client, with no additional network calls.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;p&gt;Some issues show up repeatedly in real projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generating sprite sheets synchronously in API requests,&lt;/li&gt;
&lt;li&gt;hardcoding frame sizes on the frontend,&lt;/li&gt;
&lt;li&gt;creating very large sprite sheets that hurt mobile performance,&lt;/li&gt;
&lt;li&gt;treating sprite sheets as a frontend-only concern.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sprite sheets work best when &lt;strong&gt;&lt;a href="https://nileshblog.tech/sprite-sheets-in-node-js-how-video-platforms-show-fast-hover-previews-without-loading-hundreds-of-images/" rel="noopener noreferrer"&gt;backend&lt;/a&gt; and frontend agree on a clear contract&lt;/strong&gt;.&lt;/p&gt;




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

&lt;p&gt;Sprite sheets aren’t outdated or hacky. They’re a practical performance pattern that still works because it removes the network from user interactions.&lt;/p&gt;

&lt;p&gt;If you’re building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;video players,&lt;/li&gt;
&lt;li&gt;hover previews,&lt;/li&gt;
&lt;li&gt;timeline scrubbing features,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;sprite sheets remain one of the cleanest solutions available when implemented intentionally.&lt;/p&gt;

&lt;p&gt;I write more content like this on &lt;a href="https://nileshblog.tech/" rel="noopener noreferrer"&gt;nileshblog.tech&lt;/a&gt; if you want to explore further.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>software</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Designing APIs That Are Hard to Misuse</title>
      <dc:creator>Nilesh Raut</dc:creator>
      <pubDate>Sat, 10 Jan 2026 18:30:00 +0000</pubDate>
      <link>https://dev.to/speaklouder/designing-apis-that-are-hard-to-misuse-5d6b</link>
      <guid>https://dev.to/speaklouder/designing-apis-that-are-hard-to-misuse-5d6b</guid>
      <description>&lt;p&gt;Most backend bugs don’t happen because developers are careless.&lt;br&gt;
They happen because &lt;strong&gt;APIs are easy to misuse&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If an API allows the wrong thing, someone will eventually do it — intentionally or not. Senior engineers know this, and they design APIs that &lt;strong&gt;guide correct usage and make incorrect usage difficult&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This post is about how experienced engineers think when designing APIs that survive real-world use.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Core Principle: Assume Misuse, Not Malice
&lt;/h2&gt;

&lt;p&gt;When &lt;a href="https://nileshblog.tech/designing-apis-that-are-hard-to-misuse/" rel="noopener noreferrer"&gt;designing an API&lt;/a&gt;, don’t assume:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;consumers will read the docs carefully,&lt;/li&gt;
&lt;li&gt;inputs will always be valid,&lt;/li&gt;
&lt;li&gt;calls will be made in the correct order.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assume instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;someone will misunderstand it,&lt;/li&gt;
&lt;li&gt;someone will skip validation,&lt;/li&gt;
&lt;li&gt;someone will copy-paste an example without thinking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good API doesn’t rely on “being used correctly.”&lt;br&gt;
It &lt;strong&gt;enforces correctness by design&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Clear Inputs, Clear Outputs
&lt;/h2&gt;

&lt;p&gt;Ambiguous APIs invite misuse.&lt;/p&gt;

&lt;p&gt;Bad example:&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;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/updateUser&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does this update?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name?&lt;/li&gt;
&lt;li&gt;email?&lt;/li&gt;
&lt;li&gt;password?&lt;/li&gt;
&lt;li&gt;all of them?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Better:&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;PATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/users/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;/email&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;the intent is clear,&lt;/li&gt;
&lt;li&gt;the scope is limited,&lt;/li&gt;
&lt;li&gt;misuse becomes harder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If an API endpoint can do “too many things,” it will eventually do the wrong one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Make Invalid States Impossible
&lt;/h2&gt;

&lt;p&gt;Senior engineers try to design APIs where &lt;strong&gt;invalid states cannot exist&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, instead of:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deleted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;p&gt;Design it so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a user cannot be both active and deleted,&lt;/li&gt;
&lt;li&gt;the API does not accept conflicting inputs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your API allows contradictory data, the bug isn’t in the client — it’s in the design.&lt;/p&gt;




&lt;h2&gt;
  
  
  Use Explicit Errors, Not Silent Defaults
&lt;/h2&gt;

&lt;p&gt;Silent behavior is dangerous.&lt;/p&gt;

&lt;p&gt;Bad design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing field → default value applied&lt;/li&gt;
&lt;li&gt;invalid input → ignored&lt;/li&gt;
&lt;li&gt;partial failure → success response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes bugs invisible.&lt;/p&gt;

&lt;p&gt;Better design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reject invalid input loudly,&lt;/li&gt;
&lt;li&gt;return clear error messages,&lt;/li&gt;
&lt;li&gt;fail fast and early.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;APIs should &lt;strong&gt;teach consumers how to use them correctly&lt;/strong&gt; through errors.&lt;/p&gt;




&lt;h2&gt;
  
  
  Avoid “Magic” Behavior
&lt;/h2&gt;

&lt;p&gt;Magic APIs feel convenient at first — and painful later.&lt;/p&gt;

&lt;p&gt;Examples of magic behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;auto-creating resources without saying so,&lt;/li&gt;
&lt;li&gt;silently retrying without limits,&lt;/li&gt;
&lt;li&gt;changing behavior based on hidden flags.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If something important happens, make it explicit.&lt;/p&gt;

&lt;p&gt;Good APIs are boring.&lt;br&gt;
Boring APIs are predictable.&lt;/p&gt;


&lt;h2&gt;
  
  
  Idempotency Matters More Than You Think
&lt;/h2&gt;

&lt;p&gt;In real systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;requests get retried,&lt;/li&gt;
&lt;li&gt;clients time out,&lt;/li&gt;
&lt;li&gt;networks fail.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If calling an API twice causes unintended side effects, it will break in production.&lt;/p&gt;

&lt;p&gt;Design APIs so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repeated requests are safe,&lt;/li&gt;
&lt;li&gt;duplicate calls don’t corrupt state,&lt;/li&gt;
&lt;li&gt;clients don’t need complex retry logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This alone prevents many production incidents.&lt;/p&gt;


&lt;h2&gt;
  
  
  Design for the Future Consumer
&lt;/h2&gt;

&lt;p&gt;The person using your API in six months:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;might not be you,&lt;/li&gt;
&lt;li&gt;might not know the context,&lt;/li&gt;
&lt;li&gt;might be under pressure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can this API be misunderstood?&lt;/li&gt;
&lt;li&gt;Can it be called in the wrong order?&lt;/li&gt;
&lt;li&gt;Can misuse cause data corruption?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the answer is “yes,” redesign.&lt;/p&gt;


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

&lt;p&gt;Many production bugs come from APIs like:&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;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/processPayment&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Called twice → double charge.&lt;/p&gt;

&lt;p&gt;A better design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;separate intent from execution,&lt;/li&gt;
&lt;li&gt;require idempotency keys,&lt;/li&gt;
&lt;li&gt;make side effects explicit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The extra effort up front saves incidents later.&lt;br&gt;
&lt;a href="https://nileshblog.tech/" rel="noopener noreferrer"&gt;🔗 Check out our blog site for more: nileshblog.tech&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;APIs are contracts, not just endpoints.&lt;/p&gt;

&lt;p&gt;A well-designed API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;limits what can go wrong,&lt;/li&gt;
&lt;li&gt;makes correct usage obvious,&lt;/li&gt;
&lt;li&gt;makes incorrect usage difficult,&lt;/li&gt;
&lt;li&gt;protects the system from human error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Senior engineers don’t just design APIs that work —&lt;br&gt;
they design APIs that &lt;strong&gt;are hard to misuse&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>architecture</category>
      <category>api</category>
      <category>design</category>
    </item>
  </channel>
</rss>
