<?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: Prajwal Gaonkar </title>
    <description>The latest articles on DEV Community by Prajwal Gaonkar  (@opprajwal).</description>
    <link>https://dev.to/opprajwal</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2042360%2F81e34c4a-5593-4e80-9237-81c712f0078b.png</url>
      <title>DEV Community: Prajwal Gaonkar </title>
      <link>https://dev.to/opprajwal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/opprajwal"/>
    <language>en</language>
    <item>
      <title>How the JavaScript Event Loop Creates the Illusion of Multithreading</title>
      <dc:creator>Prajwal Gaonkar </dc:creator>
      <pubDate>Sat, 04 Apr 2026 16:22:56 +0000</pubDate>
      <link>https://dev.to/opprajwal/how-the-javascript-event-loop-creates-the-illusion-of-multithreading-1ie9</link>
      <guid>https://dev.to/opprajwal/how-the-javascript-event-loop-creates-the-illusion-of-multithreading-1ie9</guid>
      <description>&lt;p&gt;If you’ve worked with JavaScript, you’ve probably heard:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“JavaScript is single-threaded.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then immediately wondered:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Then how does it handle multiple things at once?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This confusion usually comes from one misleading idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;JavaScript does NOT simulate multithreading — it achieves concurrency by avoiding blocking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s break this down clearly.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Core Truth
&lt;/h1&gt;

&lt;p&gt;JavaScript runs on a &lt;strong&gt;single thread&lt;/strong&gt;.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;One call stack&lt;/li&gt;
&lt;li&gt;One task at a time&lt;/li&gt;
&lt;li&gt;No parallel execution of your JS code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if that’s true… how does it handle multiple tasks?&lt;/p&gt;




&lt;h1&gt;
  
  
  The Real Trick: Don’t Do the Work
&lt;/h1&gt;

&lt;p&gt;Instead of running everything itself, JavaScript:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Executes fast tasks immediately&lt;/li&gt;
&lt;li&gt;Delegates slow tasks to the runtime (browser / Node.js)&lt;/li&gt;
&lt;li&gt;Continues executing other code&lt;/li&gt;
&lt;li&gt;Handles results later&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the entire model.&lt;/p&gt;




&lt;h1&gt;
  
  
  The System Behind It
&lt;/h1&gt;

&lt;p&gt;JavaScript relies on four components:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Call Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Executes code&lt;/li&gt;
&lt;li&gt;One function at a time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Runtime (Browser / Node.js)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Handles timers, network, etc.&lt;/li&gt;
&lt;li&gt;Uses background threads internally&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Callback Queue
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Stores completed async tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Event Loop
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Moves tasks from queue → stack when stack is empty&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Step-by-Step Example
&lt;/h1&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;Start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&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;Async Task&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="mi"&gt;1000&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;End&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Execution Flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Run synchronous code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start
End
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Delegate async work
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Timer is handled by runtime&lt;/li&gt;
&lt;li&gt;JavaScript does NOT wait&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Continue execution
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;JS thread is now free&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Task completes in background
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Callback goes to queue&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 5: Event loop executes it
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Async Task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Why This Feels Like Multithreading
&lt;/h1&gt;

&lt;p&gt;From the outside, it looks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple tasks are in progress&lt;/li&gt;
&lt;li&gt;Results come back later&lt;/li&gt;
&lt;li&gt;Nothing blocks execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates the illusion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task A running
Task B running
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But internally, it’s actually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Delegate Task A
Run Task B
Handle Task A result later
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Important Distinction: Concurrency vs Parallelism
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Java (Multithreading → Parallelism)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Multiple threads run at the same time&lt;/li&gt;
&lt;li&gt;Execution overlaps
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Thread 1: █ █ █ █
Thread 2: █ █ █ █
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  JavaScript (Event Loop → Concurrency)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;One task at a time&lt;/li&gt;
&lt;li&gt;No overlap in execution
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Main Task: ██████
Async Task:      ██████
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Why Your Loop Example Didn’t Look Concurrent
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setTimeout&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;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&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;Async Task:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&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;Main Thread:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&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;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Main Thread: 0
Main Thread: 1
Main Thread: 2
Async Task: 0
Async Task: 1
Async Task: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The loop is &lt;strong&gt;blocking&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;JavaScript cannot pause it&lt;/li&gt;
&lt;li&gt;Event loop runs only after it finishes&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;JavaScript never interrupts a running task&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Where Multithreading Actually Exists
&lt;/h1&gt;

&lt;p&gt;JavaScript itself is single-threaded, but the environment is not.&lt;/p&gt;

&lt;p&gt;Background threads are used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Timers&lt;/li&gt;
&lt;li&gt;Network requests&lt;/li&gt;
&lt;li&gt;File system (Node.js)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your JavaScript code never runs in parallel unless you explicitly use workers&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  When JavaScript Truly Becomes Multithreaded
&lt;/h1&gt;

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

&lt;ul&gt;
&lt;li&gt;Web Workers (browser)&lt;/li&gt;
&lt;li&gt;Worker Threads (Node.js)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only then do you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parallel execution&lt;/li&gt;
&lt;li&gt;Interleaved output&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Why This Design Works
&lt;/h1&gt;

&lt;p&gt;This model gives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non-blocking execution&lt;/li&gt;
&lt;li&gt;High performance for I/O&lt;/li&gt;
&lt;li&gt;Simpler mental model (no locks, no race conditions)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU-heavy tasks will block everything&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Final Takeaway
&lt;/h1&gt;

&lt;p&gt;JavaScript handles multiple tasks without multithreading by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Delegating slow work to the runtime&lt;/li&gt;
&lt;li&gt;Continuing execution immediately&lt;/li&gt;
&lt;li&gt;Using the event loop to process results later&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  One-Line Summary
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;JavaScript doesn’t run multiple tasks at once — it avoids waiting by offloading work and scheduling callbacks efficiently.&lt;/p&gt;
&lt;/blockquote&gt;




</description>
      <category>javascript</category>
      <category>ai</category>
      <category>webdev</category>
      <category>development</category>
    </item>
    <item>
      <title>The Real Reason Behind Arrow Functions in JavaScript</title>
      <dc:creator>Prajwal Gaonkar </dc:creator>
      <pubDate>Sat, 28 Mar 2026 18:48:17 +0000</pubDate>
      <link>https://dev.to/opprajwal/the-real-reason-behind-arrow-functions-in-javascript-14n9</link>
      <guid>https://dev.to/opprajwal/the-real-reason-behind-arrow-functions-in-javascript-14n9</guid>
      <description>&lt;h1&gt;
  
  
  The Real Difference Between Normal Functions and Arrow Functions (Node.js)
&lt;/h1&gt;

&lt;p&gt;I’ve watched a lot of explanations about arrow functions on YouTube, and almost all of them say the same thing: “they’re just shorter functions.”&lt;/p&gt;

&lt;p&gt;That explanation feels incomplete, and honestly, a bit misleading.&lt;/p&gt;

&lt;p&gt;The problem is, it focuses only on syntax and ignores what actually changes under the hood. In JavaScript, functions are not just reusable code blocks—they also define an execution context, and a big part of that context is &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With normal functions, &lt;code&gt;this&lt;/code&gt; is dynamic. It is not fixed when you write the function. Instead, it is decided later, at the moment the function is called. That means the same function can behave differently depending on how it is invoked.&lt;/p&gt;

&lt;p&gt;Arrow functions change this behavior completely. They do not create their own &lt;code&gt;this&lt;/code&gt; at all. Instead, they capture &lt;code&gt;this&lt;/code&gt; from the surrounding scope at the time they are created, and that value never changes.&lt;/p&gt;

&lt;p&gt;So the real difference is not about shorter syntax. It is about how &lt;code&gt;this&lt;/code&gt; is handled at a fundamental level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Normal functions decide &lt;code&gt;this&lt;/code&gt; at call time (dynamic binding)&lt;/li&gt;
&lt;li&gt;Arrow functions fix &lt;code&gt;this&lt;/code&gt; at creation time (lexical binding)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the part most explanations skip, but it is the reason arrow functions were introduced in the first place.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Core Difference
&lt;/h2&gt;

&lt;p&gt;Normal functions and arrow functions differ in &lt;strong&gt;how &lt;code&gt;this&lt;/code&gt; is determined&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Normal Function
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Has its &lt;strong&gt;own &lt;code&gt;this&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;this&lt;/code&gt; is decided at &lt;strong&gt;call time&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Depends on &lt;strong&gt;who calls the function&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Arrow Function
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Does &lt;strong&gt;not have its own &lt;code&gt;this&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;this&lt;/code&gt; is taken from the &lt;strong&gt;surrounding scope&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Fixed at &lt;strong&gt;creation time&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Example in Node.js
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Normal Function
&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;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;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;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Timeout&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;_idleTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&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;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The function inside &lt;code&gt;setTimeout&lt;/code&gt; is called by Node&lt;/li&gt;
&lt;li&gt;So &lt;code&gt;this&lt;/code&gt; becomes a &lt;strong&gt;Timeout object&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Arrow Function
&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;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;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;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Output
&lt;/h3&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;greet&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;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arrow function does not create its own &lt;code&gt;this&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;It uses &lt;code&gt;this&lt;/code&gt; from &lt;code&gt;greet&lt;/code&gt;, which is &lt;code&gt;user&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Side-by-Side Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Normal Function&lt;/th&gt;
&lt;th&gt;Arrow Function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Own &lt;code&gt;this&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;this&lt;/code&gt; decided&lt;/td&gt;
&lt;td&gt;Call time&lt;/td&gt;
&lt;td&gt;Creation time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;this&lt;/code&gt; depends on&lt;/td&gt;
&lt;td&gt;Caller&lt;/td&gt;
&lt;td&gt;Surrounding scope&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Final Mental Model
&lt;/h2&gt;

&lt;p&gt;Normal function:&lt;br&gt;
"I will decide &lt;code&gt;this&lt;/code&gt; when I am called"&lt;/p&gt;

&lt;p&gt;Arrow function:&lt;br&gt;
"I will use &lt;code&gt;this&lt;/code&gt; from where I was created"&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>How AI IDEs Actually Work - Under the Hood</title>
      <dc:creator>Prajwal Gaonkar </dc:creator>
      <pubDate>Sun, 22 Mar 2026 09:59:18 +0000</pubDate>
      <link>https://dev.to/opprajwal/how-ai-ides-actually-work-under-the-hood-1ih4</link>
      <guid>https://dev.to/opprajwal/how-ai-ides-actually-work-under-the-hood-1ih4</guid>
      <description>&lt;p&gt;When we ask an agentic IDE like antigravity to &lt;em&gt;“explain this”&lt;/em&gt; or &lt;em&gt;“write code like this”&lt;/em&gt;, what actually changes?&lt;/p&gt;

&lt;p&gt;And how does it return exactly what we asked for?&lt;/p&gt;

&lt;p&gt;Let’s break down what’s happening under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  Overall Workflow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Prompt
↓
Context Builder (files, code, selection, search)
↓
LLM (predicts next action)
↓
Tool Call (if needed)
↓
Execution Layer (file update / command run)
↓
Result returned
↓
LLM again (decides next step)
↓
Final response / more actions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  1. It Starts With Context — Not Your Prompt
&lt;/h2&gt;

&lt;p&gt;The IDE does NOT send only your prompt.&lt;/p&gt;

&lt;p&gt;It constructs a combined input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prompt + Code + Context + Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Context includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current file&lt;/li&gt;
&lt;li&gt;Selected code&lt;/li&gt;
&lt;li&gt;Nearby code&lt;/li&gt;
&lt;li&gt;Related files (via search)&lt;/li&gt;
&lt;li&gt;Available tools&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Context Window — Why Results Differ
&lt;/h2&gt;

&lt;p&gt;LLMs operate within a limited context window.&lt;/p&gt;

&lt;p&gt;They:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;only see what is provided&lt;/li&gt;
&lt;li&gt;do not understand your entire project&lt;/li&gt;
&lt;li&gt;do not know your intent beyond context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;there is a reason why IDE's perform better with developers then so called non devs as the context differs in both cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. No Explain Mode vs Write Mode
&lt;/h2&gt;

&lt;p&gt;There is no mode switch.&lt;/p&gt;

&lt;p&gt;The model predicts the best output format.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: Explain this function
Output: Plain text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: Fix password validation
Output: Tool call
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Tools — The Execution Layer
&lt;/h2&gt;

&lt;p&gt;AI does NOT modify files directly.&lt;br&gt;
Tools are just predefined functions.&lt;br&gt;
It calls tools like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;read_file&lt;/li&gt;
&lt;li&gt;search_code&lt;/li&gt;
&lt;li&gt;apply_patch&lt;/li&gt;
&lt;li&gt;run_terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"apply_patch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"args"&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;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auth.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"patch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"- if (password == null)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;+ if (!password || password.length &amp;lt; 6)"&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;h2&gt;
  
  
  5. How Code Is Edited
&lt;/h2&gt;

&lt;p&gt;AI uses pattern-based editing.&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 diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- if (password == null)
&lt;/span&gt;&lt;span class="gi"&gt;+ if (!password || password.length &amp;lt; 6)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why not line numbers?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They change&lt;/li&gt;
&lt;li&gt;Code shifts&lt;/li&gt;
&lt;li&gt;Patterns are more stable&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Feedback Loop
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Think → Act → Observe → Repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Final Understanding
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AI decides&lt;/li&gt;
&lt;li&gt;Tools execute&lt;/li&gt;
&lt;li&gt;Context drives everything&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AI only knows what you show it&lt;/li&gt;
&lt;li&gt;Better context → better output&lt;/li&gt;
&lt;li&gt;Real skill = giving the right context&lt;/li&gt;
&lt;li&gt;these IDE's are more than what i mentioned but this part is the one of the most interesting and important part to learn.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;As we now understood abt tools the best thing to know next is MCP protocols&lt;br&gt;
.&lt;/p&gt;

&lt;p&gt;stayy tunedd!!!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
      <category>tooling</category>
    </item>
    <item>
      <title>You Can’t Secure Public APIs — You Can Only Control Them</title>
      <dc:creator>Prajwal Gaonkar </dc:creator>
      <pubDate>Sat, 21 Mar 2026 04:55:05 +0000</pubDate>
      <link>https://dev.to/opprajwal/you-cant-secure-public-apis-you-can-only-control-them-3oig</link>
      <guid>https://dev.to/opprajwal/you-cant-secure-public-apis-you-can-only-control-them-3oig</guid>
      <description>&lt;p&gt;While building my public form system, I initially thought security meant restricting frontend access, using tokens, and enabling CORS. &lt;/p&gt;

&lt;p&gt;But after going deeper, I realized something fundamental: &lt;strong&gt;I was securing the frontend… not the API.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Attackers don’t use your frontend. They don’t click buttons. They go straight to your API.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The CORS Illusion
&lt;/h2&gt;

&lt;p&gt;I assumed CORS would protect my API. But CORS is a browser-only safety rail. It does &lt;strong&gt;NOT&lt;/strong&gt; block requests; it only blocks browsers from reading responses.&lt;/p&gt;

&lt;p&gt;This still works perfectly:&lt;br&gt;
&lt;code&gt;curl https://your-api.com/submit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Reality:&lt;/strong&gt; Your backend still executes logic. Your database can still be modified. CORS protects users, not your server.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Tokens Are Not Enough
&lt;/h2&gt;

&lt;p&gt;I implemented CSPRNG tokens and one-time validation. This made tokens unguessable, but it didn't make them &lt;strong&gt;restricted&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;If your token endpoint is public, anyone can do:&lt;br&gt;
&lt;code&gt;curl https://your-api.com/get-token&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The issue wasn’t token security. &lt;strong&gt;It was token issuance.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The Shift to Token Binding &amp;amp; DBSC
&lt;/h2&gt;

&lt;p&gt;The idea of Token Binding is that a token should only be usable by the client that received it.&lt;/p&gt;

&lt;p&gt;In 2026, we’ve moved past the old TLS Token Binding (which browsers like Chrome removed) to &lt;strong&gt;DBSC (Device Bound Session Credentials)&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How DBSC Works:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Hardware Key:&lt;/strong&gt; The device generates a key pair in the TPM (Security Chip).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binding:&lt;/strong&gt; The server binds the session token to the public key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proof:&lt;/strong&gt; Every request must be signed by that hardware key.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Does this stop a CLI attacker?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Case 1 (Token Theft):&lt;/strong&gt; Attacker steals your token. They can't sign the request without your hardware. &lt;strong&gt;SUCCESS.&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case 2 (The CLI "Guy"):&lt;/strong&gt; The attacker uses their own CLI to generate a key, gets a token, and signs the request. &lt;strong&gt;FAILURE.&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Insight:&lt;/strong&gt; DBSC prevents &lt;em&gt;misuse&lt;/em&gt;, not &lt;em&gt;malicious usage&lt;/em&gt;. &lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Real Solution: Zero Trust
&lt;/h2&gt;

&lt;p&gt;If you cannot stop a CLI attacker from acting like a valid client, you must change your mindset: &lt;strong&gt;Assume every request is malicious until proven otherwise.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You don't secure public APIs by blocking access; you secure them by &lt;strong&gt;controlling behavior.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The "One-Stop" System Design
&lt;/h2&gt;

&lt;p&gt;To protect a public form, you need a layered pipeline that makes abuse expensive and slow.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Defensive Pipeline:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limiting:&lt;/strong&gt; Control the volume.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JS Challenge / Turnstile:&lt;/strong&gt; Stop simple CLI scripts that can't execute JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TLS Fingerprinting (JA4):&lt;/strong&gt; Identify if the "handshake" comes from a browser or a library like &lt;code&gt;curl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Issuance Control:&lt;/strong&gt; Only issue tokens after the challenge is passed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency:&lt;/strong&gt; Ensure the same "attack" packet can't be processed twice.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  6. Key Techniques for 2026
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reject Early:&lt;/strong&gt; Do cheap checks (IP Rate Limits) before expensive checks (DB lookups).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Binding:&lt;/strong&gt; Bind tokens to the IP and User-Agent. If they change mid-session, kill the token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make it Expensive:&lt;/strong&gt; Force attackers to use residential proxies and headless browsers (Puppeteer). When the cost of the attack exceeds the value of the data, the attacker leaves.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔗 Code &amp;amp; Implementation
&lt;/h3&gt;

&lt;p&gt;Check out the full implementation and experiments here:&lt;br&gt;
👉 &lt;a href="https://github.com/OP-Prajwal/publicForm" rel="noopener noreferrer"&gt;github.com/OP-Prajwal/publicForm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>backend</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building an Unbreakable Public Form: From Concept to Production Backend</title>
      <dc:creator>Prajwal Gaonkar </dc:creator>
      <pubDate>Fri, 20 Mar 2026 14:52:34 +0000</pubDate>
      <link>https://dev.to/opprajwal/building-an-unbreakable-public-form-from-concept-to-production-backend-1c4o</link>
      <guid>https://dev.to/opprajwal/building-an-unbreakable-public-form-from-concept-to-production-backend-1c4o</guid>
      <description>&lt;p&gt;If you caught my &lt;a href="https://dev.to/opprajwal/making-a-public-form-secure-tokens-idempotency-real-world-backend-design-4358"&gt;previous blog post&lt;/a&gt;, we explored the high-level concepts of securing public forms: IP blocking, session tokens, idempotency, and CAPTCHAs. We talked about &lt;em&gt;what&lt;/em&gt; needed to be done to stop bots and duplicate data.&lt;/p&gt;

&lt;p&gt;But conceptual theory only gets you so far. When you sit down to actually write the code, the reality of race conditions, database locks, and user behavior hits you fast. Today, we are going completely under the hood. We're looking at the exact end-to-end system design of how those ideas come together into a real, production-ready Node.js backend. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Want to jump straight to the code?&lt;/strong&gt; The entire repository is open-source and available here: &lt;a href="https://github.com/OP-Prajwal/publicForm" rel="noopener noreferrer"&gt;OP-Prajwal/publicForm&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. The Problem Statement
&lt;/h2&gt;

&lt;p&gt;Building a form for logged-in users is straightforward because you have a user ID. But public forms—like contact pages or recruitment applications—are entirely different. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Authentication:&lt;/strong&gt; We don't know who is making the request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Wi-Fi:&lt;/strong&gt; We can't strictly ban an IP address permanently without risking locking out an entire dorm room or office of legitimate users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bot Spam:&lt;/strong&gt; Within hours of going live, bots will find your endpoint and try to drop malicious payloads or thousands of fake entries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Impatient User:&lt;/strong&gt; A real human on a laggy 3G connection clicks "Submit", nothing happens instantly, so they furiously click "Submit" six more times. Without safeguards, you now have six identical records in your database.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. The High-Level Architecture
&lt;/h2&gt;

&lt;p&gt;To solve all of this, we need a layered defense. We can't rely on just a CAPTCHA or just an IP limit. The architecture acts like a funnel, rejecting bad actors at the cheapest possible computing layer before allowing data into the database structure.&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%2Fwusfhpway74kfrs3lxq4.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%2Fwusfhpway74kfrs3lxq4.png" alt="Secure Public Form System Architecture" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Interactive architecture diagram available on &lt;a href="https://app.eraser.io/workspace/LkWjyTpoFz7Yj9nghVDR?origin=share" rel="noopener noreferrer"&gt;Eraser.io&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The Pipeline:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;User → Rate Limiter → CAPTCHA → Idempotency Check → Token Validation → Database&lt;/code&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Step-by-Step Request Flow
&lt;/h2&gt;

&lt;p&gt;Here is the exact sequence of events when a user interacts with our system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User loads the form:&lt;/strong&gt; The React frontend silently makes a &lt;code&gt;GET&lt;/code&gt; request to the backend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server generates a secure token:&lt;/strong&gt; The backend generates a Cryptographically Secure Pseudorandom (CSPRNG) token, saves it to the database, and sends it to the frontend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User submits the form:&lt;/strong&gt; The user fills the data, solves the CAPTCHA silently, and hits submit. The frontend generates a unique UUID (the Idempotency Key) and sends everything to the server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting:&lt;/strong&gt; Express middleware checks if this IP is making too many requests too fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CAPTCHA validation:&lt;/strong&gt; The controller immediately asks Cloudflare if the human actually solved the challenge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency check:&lt;/strong&gt; The database checks if this exact UUID has been seen recently. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token validation (atomic):&lt;/strong&gt; The backend verifies the CSPRNG token is valid and immediately burns it so it can never be used again.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store in DB:&lt;/strong&gt; Only after surviving this is the data finally inserted into the database.&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  4. Implementation Details in Node.js
&lt;/h2&gt;

&lt;p&gt;Let's look at how we actually built this backend. We utilized an Express.js middleware-based architecture to keep our routing clean:&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;router&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;/submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;formLimiter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;submitForm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token Generation:&lt;/strong&gt; We used Node's native &lt;code&gt;crypto&lt;/code&gt; library to generate tokens (&lt;code&gt;crypto.randomBytes(32).toString('hex')&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency:&lt;/strong&gt; When the user clicks submit, the client generates a key using &lt;code&gt;crypto.randomUUID()&lt;/code&gt;. We store this key in an &lt;code&gt;Idempotency&lt;/code&gt; MongoDB collection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Atomic Validation:&lt;/strong&gt; We execute &lt;code&gt;findOneAndUpdate()&lt;/code&gt; in Mongoose to verify and "burn" the token in the exact same database operation to prevent race conditions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. CSPRNG Tokens: Why Randomness Matters
&lt;/h2&gt;

&lt;p&gt;A session token is only as good as its un-guessability. If you generate tokens using something predictable like &lt;code&gt;Math.random()&lt;/code&gt; or a timestamp, a sophisticated bot script can mathematically guess the next token your server will issue, completely bypassing the requirement to load your frontend.&lt;/p&gt;

&lt;p&gt;By using a CSPRNG (Cryptographically Secure Pseudorandom Number Generator), we lean on the operating system's entropy pool. It is practically impossible for an attacker to predict a 32-byte hex string.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Idempotency Keys: Taming the Double-Click
&lt;/h2&gt;

&lt;p&gt;Idempotency is just a fancy word for a simple concept: doing the exact same thing twice should yield the same result without causing side effects.&lt;/p&gt;

&lt;p&gt;When our user double-clicks "Submit", two identical network requests fire simultaneously. Both carry the exact same payload and the exact same &lt;code&gt;idempotencyKey&lt;/code&gt; UUID generated by React. &lt;/p&gt;

&lt;p&gt;When the backend receives the first request, it logs the key with a status of &lt;code&gt;PROCESSING&lt;/code&gt;. If the second request arrives, our system recognizes the UUID and drops the duplicate request without inserting a cloned record into the main database. &lt;/p&gt;




&lt;h2&gt;
  
  
  7. Defeating Race Conditions
&lt;/h2&gt;

&lt;p&gt;Idempotency sounds easy until you encounter concurrency. &lt;/p&gt;

&lt;p&gt;Imagine those two identical requests hit the Node.js server at the exact same microsecond. Both queries check the database. Both queries see that the Idempotency Key doesn't exist yet. Both queries try to insert the record.&lt;/p&gt;

&lt;p&gt;If we handled this with standard Javascript &lt;code&gt;if/else&lt;/code&gt; logic, both would succeed. To fix this natively, we don't need complex database transactions. We rely on the database layer to act as our atomic lock. &lt;/p&gt;

&lt;h3&gt;
  
  
  In MongoDB (Mongoose)
&lt;/h3&gt;

&lt;p&gt;We literally just add a &lt;code&gt;unique: true&lt;/code&gt; index to the Idempotency Key in our schema:&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;idempotencySchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;unique&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;// MongoDB enforces atomicity here&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PROCESSING&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;The first request successfully claims the lock and inserts the record. The second concurrent request is instantly slapped down by MongoDB throwing an &lt;strong&gt;&lt;code&gt;E11000 Duplicate Key Error&lt;/code&gt;&lt;/strong&gt;. We catch that error in our backend and safely drop the duplicate. Race condition solved.&lt;/p&gt;

&lt;h3&gt;
  
  
  In SQL (PostgreSQL / MySQL)
&lt;/h3&gt;

&lt;p&gt;If you are building this in a relational database, the exact same principle applies. You create a &lt;code&gt;UNIQUE&lt;/code&gt; constraint on the column:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;idempotency_locks&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="s1"&gt;'PROCESSING'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Or adding it to an existing table:&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;idempotency_locks&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;unique_idemp_key&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When two identical &lt;code&gt;INSERT&lt;/code&gt; commands execute at the exact same time, the first one writes the row, and the database engine blocks the second one from executing, instantly throwing a &lt;strong&gt;Unique Violation Error (e.g., Code 23505 in Postgres)&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Rate Limiting: The Outer Shield
&lt;/h2&gt;

&lt;p&gt;If we have all of these protections, why do we still need Rate Limiting?&lt;/p&gt;

&lt;p&gt;Because database queries cost CPU cycles. If a malicious script attempts to submit 5,000 forms a second using fake CAPTCHAs and fake tokens, your Node server is going to spend all of its resources connecting to MongoDB just to reject them. &lt;/p&gt;

&lt;p&gt;The Rate Limiter (&lt;code&gt;express-rate-limit&lt;/code&gt;) sits at the very outer edge of the middleware. If an IP exceeds 20 requests a minute, it gets blocked entirely before the Node controller even parses the JSON payload. &lt;/p&gt;




&lt;h2&gt;
  
  
  9. CAPTCHA: The Bouncer
&lt;/h2&gt;

&lt;p&gt;Why is the CAPTCHA validation the very first thing we do inside the main controller? &lt;/p&gt;

&lt;p&gt;We use Cloudflare Turnstile to verify humans. Pinging Cloudflare's API is vastly cheaper and safer for our server than running multiple MongoDB queries. If the payload arrives with a missing or invalid CAPTCHA token, we immediately drop the request with a &lt;code&gt;400 Bad Request&lt;/code&gt;. We don't bother checking Idempotency. We don't bother checking the CSPRNG token. &lt;/p&gt;

&lt;p&gt;If you aren't human, you don't get past the lobby.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. The Final System Flow Summarized
&lt;/h2&gt;

&lt;p&gt;When you step back, the elegance of the system reveals itself. We built a heavily guarded fortress for a simple form payload:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CAPTCHA&lt;/strong&gt; (Is it a bot?) → &lt;strong&gt;Rate Limit&lt;/strong&gt; (Is it spamming?) → &lt;strong&gt;Idempotency&lt;/strong&gt; (Is it a double-click duplicate?) → &lt;strong&gt;Token&lt;/strong&gt; (Is it a forged, headless request?) → &lt;strong&gt;Database&lt;/strong&gt; (Safe and clean).&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Key Learnings: Layered Defense
&lt;/h2&gt;

&lt;p&gt;The biggest takeaway from building this is the concept of layered defense. &lt;/p&gt;

&lt;p&gt;No single security measure is flawless. Rate limits can be bypassed using VPNs or distributed botnets. CAPTCHAs can occasionally be solved by advanced solvers. Tokens can be harvested. But when you stack them sequentially, the cost and difficulty for an attacker skyrocket exponentially. Real-world backend thinking is about assuming every single layer will eventually fail—and ensuring the layer behind it is ready to catch the mistake.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Conclusion
&lt;/h2&gt;

&lt;p&gt;What started as an innocent HTML form transformed into a massive system design problem. Public-facing endpoints are arguably some of the most difficult pieces of infrastructure to secure properly because you have absolutely zero trust in the client interacting with it.&lt;/p&gt;

&lt;p&gt;If you are just building a quick side project, a simple reCAPTCHA might be enough. But if you want to build at enterprise grade, learning how to juggle atomic databases, idempotency keys, and session validation is invaluable. It shifts your mindset from "How do I make this work?" to "How do I make this unbreakable?"&lt;/p&gt;

</description>
      <category>backend</category>
      <category>node</category>
      <category>security</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Making a Public Form Secure: Tokens, Idempotency &amp; Real-World Backend Design</title>
      <dc:creator>Prajwal Gaonkar </dc:creator>
      <pubDate>Thu, 19 Mar 2026 06:46:00 +0000</pubDate>
      <link>https://dev.to/opprajwal/making-a-public-form-secure-tokens-idempotency-real-world-backend-design-4358</link>
      <guid>https://dev.to/opprajwal/making-a-public-form-secure-tokens-idempotency-real-world-backend-design-4358</guid>
      <description>&lt;p&gt;I thought building a form was easy… until I tried making it secure.&lt;/p&gt;

&lt;p&gt;While designing a recruitment form for a college club, I realized that the real challenge is not collecting data — it is making sure the system behaves correctly under real-world conditions.&lt;/p&gt;

&lt;p&gt;Let’s walk through how I approached this problem step by step.&lt;/p&gt;




&lt;h2&gt;Understanding the Problem&lt;/h2&gt;

&lt;p&gt;The form was public. Users could submit it using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mobile data&lt;/li&gt;
&lt;li&gt;College Wi-Fi&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common beginner approach is to block users based on IP address after submission.&lt;/p&gt;

&lt;p&gt;At first glance, this seems reasonable.&lt;/p&gt;

&lt;p&gt;But in real-world networks, especially Wi-Fi, multiple users share the same public IP due to NAT.&lt;/p&gt;

&lt;pre&gt;100 users → 1 IP&lt;/pre&gt;

&lt;p&gt;If we block that IP, we end up blocking everyone connected to that network.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Clearly, this approach fails.&lt;/b&gt;&lt;/p&gt;




&lt;h2&gt;Solution 1 — &lt;u&gt;IP-Based Blocking&lt;/u&gt;
&lt;/h2&gt;

&lt;h3&gt;The idea&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Track submissions by IP&lt;/li&gt;
&lt;li&gt;Block further requests from the same IP&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Why it seems useful&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Simple to implement&lt;/li&gt;
&lt;li&gt;Works in small, isolated environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Drawbacks&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Breaks in shared networks (Wi-Fi, offices, colleges)&lt;/li&gt;
&lt;li&gt;Blocks legitimate users&lt;/li&gt;
&lt;li&gt;Not reliable in real-world systems&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;Solution 2 — &lt;u&gt;One-Time Form Tokens&lt;/u&gt;
&lt;/h2&gt;

&lt;h3&gt;The idea&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;When a user loads the form, the server generates a unique token&lt;/li&gt;
&lt;li&gt;The token is sent to the client&lt;/li&gt;
&lt;li&gt;On submission, the server validates and marks the token as used&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Why it works&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prevents duplicate submissions&lt;/li&gt;
&lt;li&gt;Stops accidental double clicks&lt;/li&gt;
&lt;li&gt;Prevents replaying the same request&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Drawbacks&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Users can reload the page and get a new token&lt;/li&gt;
&lt;li&gt;Bots can repeatedly request new tokens&lt;/li&gt;
&lt;li&gt;Does not prevent automated spam&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;Solution 3 — &lt;u&gt;Idempotency Keys&lt;/u&gt;
&lt;/h2&gt;

&lt;h3&gt;The idea&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Each logical request is assigned a unique idempotency key&lt;/li&gt;
&lt;li&gt;The server stores the key along with the response&lt;/li&gt;
&lt;li&gt;If the same key is used again, the server returns the stored response instead of processing the request again&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Example&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;POST /submit
Idempotency-Key: abc123&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Why it works&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prevents duplicate processing&lt;/li&gt;
&lt;li&gt;Handles retries safely&lt;/li&gt;
&lt;li&gt;Ensures operations execute only once&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Drawbacks&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Requires additional storage (Redis/DB)&lt;/li&gt;
&lt;li&gt;Needs careful handling of request validation&lt;/li&gt;
&lt;li&gt;Does not stop bots generating new requests with new keys&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;Solution 4 — &lt;u&gt;Honeypot Fields&lt;/u&gt;
&lt;/h2&gt;

&lt;h3&gt;The idea&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add a hidden input field that users cannot see&lt;/li&gt;
&lt;li&gt;Bots often fill all fields automatically&lt;/li&gt;
&lt;li&gt;If this field is filled, reject the request&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Why it works&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Very simple to implement&lt;/li&gt;
&lt;li&gt;Effectively blocks basic bots&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Drawbacks&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Advanced bots can bypass it&lt;/li&gt;
&lt;li&gt;Not sufficient as a standalone solution&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;Solution 5 — &lt;u&gt;CAPTCHA&lt;/u&gt;
&lt;/h2&gt;

&lt;h3&gt;The idea&lt;/h3&gt;

&lt;ul&gt;&lt;li&gt;Verify that the user is human before accepting submission&lt;/li&gt;&lt;/ul&gt;

&lt;h3&gt;Examples&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;“I am not a robot”&lt;/li&gt;
&lt;li&gt;Google reCAPTCHA&lt;/li&gt;
&lt;li&gt;Cloudflare Turnstile&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Why it works&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Blocks most automated scripts&lt;/li&gt;
&lt;li&gt;Adds a strong verification layer&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Drawbacks&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Slight friction for users&lt;/li&gt;
&lt;li&gt;Can impact user experience if overused&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;What started as a simple form turned into a lesson in backend system design.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The biggest takeaway is:&lt;/b&gt;&lt;/p&gt;

&lt;blockquote&gt;There is no single solution.&lt;/blockquote&gt;

&lt;p&gt;Real systems use layered protection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP awareness (but not reliance)&lt;/li&gt;
&lt;li&gt;Tokens for request validation&lt;/li&gt;
&lt;li&gt;Idempotency for safe retries&lt;/li&gt;
&lt;li&gt;Honeypots for bot detection&lt;/li&gt;
&lt;li&gt;CAPTCHA for human verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each layer solves a different problem.&lt;/p&gt;

&lt;p&gt;Even a simple public form can reveal how real-world systems are designed to handle scale, failures, and abuse.&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>backend</category>
      <category>systemdesign</category>
      <category>cleancode</category>
    </item>
  </channel>
</rss>
