<?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: Akash Gupta</title>
    <description>The latest articles on DEV Community by Akash Gupta (@akashguptasky).</description>
    <link>https://dev.to/akashguptasky</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3862670%2Fb91ff3f8-1914-4ef4-8653-2262215a9a56.jpg</url>
      <title>DEV Community: Akash Gupta</title>
      <link>https://dev.to/akashguptasky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/akashguptasky"/>
    <language>en</language>
    <item>
      <title>How to Structure a Production-Grade Node.js + Express Backend (2026)</title>
      <dc:creator>Akash Gupta</dc:creator>
      <pubDate>Wed, 02 Sep 2026 19:55:27 +0000</pubDate>
      <link>https://dev.to/akashguptasky/how-to-structure-a-production-grade-nodejs-express-backend-2026-42n0</link>
      <guid>https://dev.to/akashguptasky/how-to-structure-a-production-grade-nodejs-express-backend-2026-42n0</guid>
      <description>&lt;h1&gt;
  
  
  How to Structure a Production-Grade Node.js + Express Backend (2026)
&lt;/h1&gt;

&lt;p&gt;Most Node.js tutorials stop at &lt;code&gt;app.get('/', ...)&lt;/code&gt;. Then you land a real project, the codebase hits 40 files, and everything lives in one 800-line &lt;code&gt;index.js&lt;/code&gt;. Been there.&lt;/p&gt;

&lt;p&gt;After building and reviewing dozens of backends, here's the structure and the handful of decisions that actually keep a Node + Express project maintainable — explained so a beginner can follow, but detailed enough to use at work today.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Layer your app: route → controller → service
&lt;/h2&gt;

&lt;p&gt;The single biggest upgrade you can make is to stop putting logic inside routes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Route&lt;/strong&gt; — only wiring. Which URL maps to which handler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controller&lt;/strong&gt; — reads the request, calls a service, sends the response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt; — the actual business logic (talks to the DB, other APIs).
&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="c1"&gt;// routes/user.routes.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;userController&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../controllers/user.controller.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;

&lt;span class="c1"&gt;// controllers/user.controller.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../services/user.service.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUser&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="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;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;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// services/user.service.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../models/User.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;findById&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&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="nf"&gt;lean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why it matters: your business logic becomes testable without HTTP, and swapping Express for Fastify later touches only the route/controller layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. A folder structure that scales
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
  config/        # env, db connection, third-party clients
  models/        # schemas
  routes/        # URL wiring only
  controllers/   # request/response glue
  services/      # business logic
  middleware/    # auth, validation, error handler
  utils/         # pure helpers
  app.js         # express app (no listen)
  server.js      # starts the server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep &lt;code&gt;app.js&lt;/code&gt; (build the app) separate from &lt;code&gt;server.js&lt;/code&gt; (start it). Your tests can import &lt;code&gt;app&lt;/code&gt; without opening a port.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Centralize config — never read &lt;code&gt;process.env&lt;/code&gt; everywhere
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// config/env.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;mongoUri&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;MONGO_URI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;jwtSecret&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;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;nodeEnv&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;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mongoUri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MONGO_URI is required&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;Reading env in one place means a missing variable fails &lt;strong&gt;loudly at startup&lt;/strong&gt;, not silently at 2 AM in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. One error handler to rule them all
&lt;/h2&gt;

&lt;p&gt;Stop writing &lt;code&gt;try/catch&lt;/code&gt; that just &lt;code&gt;res.status(500)&lt;/code&gt;. Funnel everything to a single error middleware.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// middleware/error.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;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;status&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;status&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;500&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;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// log real bugs&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="nx"&gt;status&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="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong&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="c1"&gt;// app.js (must be registered LAST)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Controllers just &lt;code&gt;next(err)&lt;/code&gt; and move on. Clean and consistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Validate input at the edge
&lt;/h2&gt;

&lt;p&gt;Never trust the request body. Validate before it reaches your service (Zod is great):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signupSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&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;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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&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;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;issues&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;h2&gt;
  
  
  6. The security basics you can't skip
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;helmet()&lt;/code&gt; for sane HTTP headers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;express-rate-limit&lt;/code&gt; on auth routes&lt;/li&gt;
&lt;li&gt;Hash passwords with &lt;code&gt;bcrypt&lt;/code&gt; (never store plaintext)&lt;/li&gt;
&lt;li&gt;Keep secrets in env, &lt;strong&gt;never&lt;/strong&gt; in the repo (add &lt;code&gt;.env&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Validate + sanitize every input (point 5)
&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;helmet&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;helmet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;rateLimit&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express-rate-limit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;helmet&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;rateLimit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;windowMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Graceful shutdown (the detail nobody teaches)
&lt;/h2&gt;

&lt;p&gt;When your host restarts the app, finish in-flight requests and close the DB cleanly:&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;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SIGTERM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Putting it together
&lt;/h2&gt;

&lt;p&gt;A good backend isn't about knowing every library — it's about &lt;strong&gt;separation of concerns, failing loudly, and never trusting input&lt;/strong&gt;. Master these seven and you're already ahead of most juniors.&lt;/p&gt;

&lt;p&gt;If you want a structured path from "first API" to "deployed, production-ready backend" — with Node.js, Express, MongoDB, MySQL and Redis — that's exactly what we teach at &lt;a href="https://asbackendinstitute.com" rel="noopener noreferrer"&gt;AS Backend Institute&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What does your Express folder structure look like? Drop it in the comments 👇&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by the team at &lt;a href="https://asbackendinstitute.com" rel="noopener noreferrer"&gt;AS Backend Institute&lt;/a&gt; — a placement-focused backend development course for aspiring developers in India.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>backend</category>
      <category>express</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A stranger's comment rewrote my retention strategy — so I shipped it the same day</title>
      <dc:creator>Akash Gupta</dc:creator>
      <pubDate>Mon, 31 Aug 2026 18:13:30 +0000</pubDate>
      <link>https://dev.to/akashguptasky/a-strangers-comment-rewrote-my-retention-strategy-so-i-shipped-it-the-same-day-46bg</link>
      <guid>https://dev.to/akashguptasky/a-strangers-comment-rewrote-my-retention-strategy-so-i-shipped-it-the-same-day-46bg</guid>
      <description>&lt;p&gt;I'm building a backend-development learning platform solo — the whole thing: Node/Express API, MongoDB, Socket, SQL, live classes, a roadmap, assignments, certificates. Real students, real fees, one developer.&lt;/p&gt;

&lt;p&gt;Last week I posted about it here. The most valuable thing that came out of it wasn't traffic — it was &lt;strong&gt;one comment.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The comment that changed my roadmap
&lt;/h2&gt;

&lt;p&gt;A developer in the comments pushed back on how I was thinking about retention. My instinct was streaks (the Duolingo flame). Their point, paraphrased:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Streaks are fragile. One missed day and streak-based motivation collapses. Track the % of active days vs total days as your internal health metric — and show the user an all-time tally instead. "You've practiced X times" survives a broken streak in a way "streak: 0" never does.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That reframed the whole thing for me. A streak is a &lt;strong&gt;motivator&lt;/strong&gt;, not a &lt;strong&gt;measure&lt;/strong&gt;. The moment it breaks, it demotivates the exact person who needed one more nudge.&lt;/p&gt;

&lt;h2&gt;
  
  
  So I shipped it — the same day
&lt;/h2&gt;

&lt;p&gt;I added a lifetime &lt;strong&gt;"days practiced"&lt;/strong&gt; count next to the streak. It counts the distinct days a student actually did the work, and it never resets — even after a missed day.&lt;/p&gt;

&lt;p&gt;Streak = the visible nudge. "You've shown up 24 times" = the thing that keeps you going after you miss a day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then I realized the bigger lesson
&lt;/h2&gt;

&lt;p&gt;That one comment was worth more than a week of my own planning. So I asked: how do I get more of this from actual users, not just from Dev.to?&lt;/p&gt;

&lt;p&gt;I built an in-app &lt;strong&gt;"Report a bug / feedback"&lt;/strong&gt; button. On the platform, once you're logged in: click your &lt;strong&gt;avatar (top-right) → Report a bug&lt;/strong&gt;, type what broke, and hit send — and it lands in a dashboard I triage every day.&lt;/p&gt;

&lt;p&gt;Try it here: &lt;strong&gt;&lt;a href="https://asbackendinstitute.com" rel="noopener noreferrer"&gt;https://asbackendinstitute.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The bet: &lt;strong&gt;your users' bugs and comments are your real roadmap.&lt;/strong&gt; Make it stupidly easy for them to hand it to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;Building solo doesn't mean building alone. The best product decisions this month didn't come from me — they came from a comment, and (now) from a feedback button. My job is mostly to &lt;strong&gt;listen fast and ship faster.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you've built something people use: what's the one piece of user feedback that changed your product the most?&lt;/p&gt;

&lt;p&gt;— Akash, solo dev, AS Backend Institute&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>webdev</category>
      <category>node</category>
      <category>startup</category>
    </item>
    <item>
      <title>15 Git Commands That Quietly Separate Juniors from Seniors</title>
      <dc:creator>Akash Gupta</dc:creator>
      <pubDate>Fri, 28 Aug 2026 08:00:53 +0000</pubDate>
      <link>https://dev.to/akashguptasky/15-git-commands-that-quietly-separate-juniors-from-seniors-a3m</link>
      <guid>https://dev.to/akashguptasky/15-git-commands-that-quietly-separate-juniors-from-seniors-a3m</guid>
      <description>&lt;p&gt;Everyone knows &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;. That's the entry fee, not the game.&lt;/p&gt;

&lt;p&gt;The developers who move fast — the ones who never lose work, never ship an ugly history, and never panic when a rebase goes sideways — all quietly share the same toolbox. It's not senior "Git magic." It's about 15 commands you can learn in an afternoon and lean on for the rest of your career.&lt;/p&gt;

&lt;p&gt;I teach backend developers over at &lt;a href="https://asbackendinstitute.com" rel="noopener noreferrer"&gt;AS Backend Institute&lt;/a&gt;, and if I had to name one skill that predicts seniority without touching a single line of application code, it's Git fluency. So here are the 15 I actually reach for every week — with the gotchas nobody warns you about.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;code&gt;git switch&lt;/code&gt; and &lt;code&gt;git restore&lt;/code&gt; — stop using &lt;code&gt;checkout&lt;/code&gt; for everything
&lt;/h2&gt;

&lt;p&gt;For years &lt;code&gt;checkout&lt;/code&gt; did two unrelated jobs: switching branches &lt;em&gt;and&lt;/em&gt; throwing away file changes. That overloading caused real accidents. Modern Git split it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch main            &lt;span class="c"&gt;# change branch&lt;/span&gt;
git switch &lt;span class="nt"&gt;-c&lt;/span&gt; feature/pay  &lt;span class="c"&gt;# create + switch&lt;/span&gt;
git restore src/app.js     &lt;span class="c"&gt;# discard changes in a file&lt;/span&gt;
git restore &lt;span class="nt"&gt;--staged&lt;/span&gt; x.js  &lt;span class="c"&gt;# unstage, keep the edits&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; &lt;code&gt;git restore &amp;lt;file&amp;gt;&lt;/code&gt; permanently discards uncommitted changes. There's no undo. Reach for it deliberately.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;code&gt;git add -p&lt;/code&gt; — commit like a surgeon
&lt;/h2&gt;

&lt;p&gt;Changed five unrelated things in one file? Don't dump them into one commit. Stage &lt;em&gt;hunks&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git walks you through each change: &lt;code&gt;y&lt;/code&gt; (stage), &lt;code&gt;n&lt;/code&gt; (skip), &lt;code&gt;s&lt;/code&gt; (split further), &lt;code&gt;e&lt;/code&gt; (edit the hunk by hand). This one habit is the difference between a readable history and a "misc fixes" graveyard.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;code&gt;git commit --amend&lt;/code&gt; — fix the last commit, not your dignity
&lt;/h2&gt;

&lt;p&gt;Forgot a file? Typo in the message? Don't add a &lt;code&gt;fix typo&lt;/code&gt; commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add forgotten.js
git commit &lt;span class="nt"&gt;--amend&lt;/span&gt; &lt;span class="nt"&gt;--no-edit&lt;/span&gt;   &lt;span class="c"&gt;# fold it in, keep the message&lt;/span&gt;
git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;             &lt;span class="c"&gt;# ...or edit the message too&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; amend rewrites the commit (new hash). Fine locally. If it's already pushed, you'll need a force push — see #13.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;code&gt;git commit --fixup&lt;/code&gt; + &lt;code&gt;--autosquash&lt;/code&gt; — amend an &lt;em&gt;old&lt;/em&gt; commit
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;--amend&lt;/code&gt; only fixes the &lt;em&gt;last&lt;/em&gt; commit. To fix one buried three commits back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;--fixup&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;              &lt;span class="c"&gt;# a marked "fixup!" commit&lt;/span&gt;
git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;--autosquash&lt;/span&gt; main        &lt;span class="c"&gt;# Git auto-orders it next to its target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the professional move most people never learn. Your fix lands exactly where it belongs, automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;code&gt;git rebase -i&lt;/code&gt; — the history editor
&lt;/h2&gt;

&lt;p&gt;Interactive rebase lets you reshape recent commits: &lt;code&gt;reword&lt;/code&gt;, &lt;code&gt;squash&lt;/code&gt;, &lt;code&gt;fixup&lt;/code&gt;, &lt;code&gt;drop&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, and reorder — just by editing a list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; HEAD~5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turn &lt;code&gt;add validation&lt;/code&gt; → &lt;code&gt;fix validation&lt;/code&gt; → &lt;code&gt;actually fix it&lt;/code&gt; into one clean &lt;code&gt;Add form validation&lt;/code&gt;. &lt;strong&gt;Rule:&lt;/strong&gt; only rewrite commits nobody else has pulled.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. &lt;code&gt;git stash&lt;/code&gt; — park work without committing junk
&lt;/h2&gt;

&lt;p&gt;Production's on fire and your feature half-builds? Stash it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash push &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"wip: checkout flow"&lt;/span&gt;   &lt;span class="c"&gt;# -u also stashes untracked files&lt;/span&gt;
git stash &lt;span class="nt"&gt;-p&lt;/span&gt;                                &lt;span class="c"&gt;# stash only selected hunks&lt;/span&gt;
git stash list
git stash show &lt;span class="nt"&gt;-p&lt;/span&gt; stash@&lt;span class="o"&gt;{&lt;/span&gt;0&lt;span class="o"&gt;}&lt;/span&gt;
git stash pop                               &lt;span class="c"&gt;# apply + remove&lt;/span&gt;
git stash apply stash@&lt;span class="o"&gt;{&lt;/span&gt;0&lt;span class="o"&gt;}&lt;/span&gt;                   &lt;span class="c"&gt;# apply, keep in list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; without &lt;code&gt;-u&lt;/code&gt;, brand-new untracked files stay behind. Always name your stashes — "future you" won't remember what &lt;code&gt;stash@{3}&lt;/code&gt; was.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. &lt;code&gt;git cherry-pick&lt;/code&gt; — grab one commit, not the whole branch
&lt;/h2&gt;

&lt;p&gt;You need &lt;em&gt;one&lt;/em&gt; commit from another branch — a config fix, a hotfix — nothing else:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cherry-pick &amp;lt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
git cherry-pick &lt;span class="nt"&gt;-x&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="c"&gt;# records "cherry picked from…" in the message&lt;/span&gt;
git cherry-pick &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="c"&gt;# apply but don't commit (batch several, then commit)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect for porting a single fix onto a release branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. &lt;code&gt;git bisect&lt;/code&gt; — binary-search the commit that broke it
&lt;/h2&gt;

&lt;p&gt;Bug appeared "sometime in the last 200 commits"? Don't guess. Let Git find it in ~8 steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect start
git bisect bad                 &lt;span class="c"&gt;# current commit is broken&lt;/span&gt;
git bisect good v1.4.0         &lt;span class="c"&gt;# this old one worked&lt;/span&gt;
&lt;span class="c"&gt;# Git checks out the midpoint — you test and mark:&lt;/span&gt;
git bisect good   &lt;span class="c"&gt;# or: git bisect bad&lt;/span&gt;
&lt;span class="c"&gt;# ...repeat until Git names the exact culprit&lt;/span&gt;
git bisect reset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even better, automate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect run npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git runs your test on each midpoint and finds the breaking commit on its own. The first time you see this work, it feels illegal.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. &lt;code&gt;git worktree&lt;/code&gt; — two branches, two folders, one repo
&lt;/h2&gt;

&lt;p&gt;The best-kept secret for context switching. Instead of stashing your feature to fix a prod bug, check the other branch out into a &lt;em&gt;separate folder&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../hotfix main
&lt;span class="c"&gt;# fix, commit, push from ../hotfix — your feature work stays untouched&lt;/span&gt;
git worktree remove ../hotfix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No stashing, no rebuild churn, no lost train of thought.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. &lt;code&gt;git log -S&lt;/code&gt; and &lt;code&gt;git log -L&lt;/code&gt; — detective mode
&lt;/h2&gt;

&lt;p&gt;"When did this line appear? Who deleted this function?"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="s2"&gt;"calculateTax"&lt;/span&gt; &lt;span class="nt"&gt;--oneline&lt;/span&gt;    &lt;span class="c"&gt;# commits that added/removed that string&lt;/span&gt;
git log &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; :calculateTax:tax.js     &lt;span class="c"&gt;# full history of one function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "pickaxe" (&lt;code&gt;-S&lt;/code&gt;) has ended more "who wrote this and why" arguments than any meeting ever will.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. &lt;code&gt;git blame -w -C&lt;/code&gt; — line-by-line history, done right
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git blame &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; src/auth.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-w&lt;/code&gt; ignores whitespace-only changes; &lt;code&gt;-C&lt;/code&gt; follows code that was moved or copied — so you blame the &lt;em&gt;real&lt;/em&gt; author, not whoever ran the formatter. Then read the commit for the &lt;em&gt;why&lt;/em&gt;, not to assign blame. 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  12. &lt;code&gt;git reflog&lt;/code&gt; — the undo button for "undo"
&lt;/h2&gt;

&lt;p&gt;Nuked a branch with a bad reset? Git logs almost every move of &lt;code&gt;HEAD&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reflog
&lt;span class="c"&gt;# 821cd77 HEAD@{1}: commit: Add authentication   ← there it is&lt;/span&gt;
git branch rescue 821cd77   &lt;span class="c"&gt;# recover it safely into a new branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limit:&lt;/strong&gt; reflog only resurrects things Git already stored (commits, stashes). Work you never committed is gone. Translation: commit early, commit often.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. &lt;code&gt;git reset --soft / --mixed / --hard&lt;/code&gt; (+ safe force push)
&lt;/h2&gt;

&lt;p&gt;One command, three levels of "go back," each answering "what happens to my changes?"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--soft&lt;/span&gt;  HEAD~1   &lt;span class="c"&gt;# undo commit, keep changes STAGED&lt;/span&gt;
git reset &lt;span class="nt"&gt;--mixed&lt;/span&gt; HEAD~1   &lt;span class="c"&gt;# undo commit, keep changes UNSTAGED (default)&lt;/span&gt;
git reset &lt;span class="nt"&gt;--hard&lt;/span&gt;  HEAD~1   &lt;span class="c"&gt;# undo commit, DISCARD changes (danger)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After any history rewrite, push safely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;--force-with-lease&lt;/span&gt;   &lt;span class="c"&gt;# refuses to clobber if someone else pushed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--force-with-lease&lt;/code&gt; over &lt;code&gt;--force&lt;/code&gt;, always. It's the difference between "oops" and "I just deleted my teammate's afternoon."&lt;/p&gt;

&lt;h2&gt;
  
  
  14. &lt;code&gt;git revert&lt;/code&gt; — undo on shared branches without rewriting history
&lt;/h2&gt;

&lt;p&gt;A bad commit is already on &lt;code&gt;main&lt;/code&gt;/&lt;code&gt;develop&lt;/code&gt;. &lt;strong&gt;Do not&lt;/strong&gt; reset + force-push a shared branch. Create an inverse commit instead:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;History stays honest: the change happened, it broke things, it was reverted — everyone can see the trail. Rule of thumb: &lt;strong&gt;shared branch → revert; private branch → reset.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  15. &lt;code&gt;git rerere&lt;/code&gt; — Git remembers how you fixed a conflict
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Reuse Recorded Resolution.&lt;/em&gt; Enable it once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; rerere.enabled &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you resolve a conflict, Git records it. Hit the &lt;em&gt;same&lt;/em&gt; conflict again (super common during long rebases) and it replays your resolution automatically. Obscure, underused, borderline magical.&lt;/p&gt;

&lt;p&gt;please checkit out this also: &lt;a href="https://dev.to/akashguptasky/a-strangers-comment-rewrote-my-retention-strategy-so-i-shipped-it-the-same-day-46bg"&gt;a-strangers-comment-rewrote-my-retention-strategy-so-i-shipped-it-the-same-day&lt;/a&gt; &lt;/p&gt;




&lt;h3&gt;
  
  
  The pattern underneath all of these
&lt;/h3&gt;

&lt;p&gt;Notice the theme: most of these exist so you can &lt;strong&gt;keep a clean, honest history&lt;/strong&gt; and &lt;strong&gt;never lose work&lt;/strong&gt;. That's really what Git seniority is — not memorizing flags, but having the reflexes to move fast without breaking things.&lt;/p&gt;

&lt;p&gt;If you're leveling up your backend skills and want more hands-on workflow stuff like this, we publish free guides over at &lt;a href="https://asbackendinstitute.com/blog" rel="noopener noreferrer"&gt;AS Backend Institute&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Which command surprised you? And what's the one intermediate command I left out that you'd fight to keep? Drop it in the comments — I always end up learning something. 👇&lt;/p&gt;

</description>
      <category>git</category>
      <category>programming</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Node.js Event Loop, Explained Simply (with Examples)</title>
      <dc:creator>Akash Gupta</dc:creator>
      <pubDate>Wed, 26 Aug 2026 17:52:09 +0000</pubDate>
      <link>https://dev.to/akashguptasky/the-nodejs-event-loop-explained-simply-with-examples-4n4g</link>
      <guid>https://dev.to/akashguptasky/the-nodejs-event-loop-explained-simply-with-examples-4n4g</guid>
      <description>&lt;p&gt;"Node.js is single-threaded" — you've heard it a hundred times. So how does it handle thousands of requests at once without freezing?&lt;/p&gt;

&lt;p&gt;The answer is the &lt;strong&gt;event loop&lt;/strong&gt;. Once it clicks, a lot of Node "magic" suddenly makes sense. Let's break it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-line mental model
&lt;/h2&gt;

&lt;p&gt;Node runs your JavaScript on &lt;strong&gt;one main thread&lt;/strong&gt;, but hands off slow work (file reads, network calls, timers) to the system, and picks up the results later via the &lt;strong&gt;event loop&lt;/strong&gt;. So one thread juggles thousands of connections — it just never sits around waiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blocking vs non-blocking
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Blocking — nothing else runs until this file is read&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;big.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Non-blocking — Node starts the read and moves on&lt;/span&gt;
&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;big.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&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="s1"&gt;done reading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;this prints FIRST&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;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this prints FIRST
done reading
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second version doesn't wait — that's the whole point.&lt;/p&gt;

&lt;h2&gt;
  
  
  The phases (simplified)
&lt;/h2&gt;

&lt;p&gt;Each loop iteration goes through phases, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Timers&lt;/strong&gt; — &lt;code&gt;setTimeout&lt;/code&gt; / &lt;code&gt;setInterval&lt;/code&gt; callbacks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poll&lt;/strong&gt; — I/O callbacks (file, network)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check&lt;/strong&gt; — &lt;code&gt;setImmediate&lt;/code&gt; callbacks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Close&lt;/strong&gt; — cleanup callbacks&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And between every phase, Node drains the &lt;strong&gt;microtask queue&lt;/strong&gt; first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Microtasks jump the line
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;process.nextTick()&lt;/code&gt; and resolved &lt;strong&gt;Promises&lt;/strong&gt; are microtasks — they run &lt;em&gt;before&lt;/em&gt; the loop moves to the next phase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&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="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="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="s1"&gt;3&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="s1"&gt;4&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;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
4
3   ← Promise (microtask) runs before setTimeout
2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most people guess &lt;code&gt;1 2 4 3&lt;/code&gt;. If you understand why it's &lt;code&gt;1 4 3 2&lt;/code&gt;, you understand the event loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  setTimeout vs setImmediate
&lt;/h2&gt;

&lt;p&gt;Inside an I/O callback, &lt;code&gt;setImmediate&lt;/code&gt; always fires before &lt;code&gt;setTimeout(fn, 0)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;f.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="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="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="s1"&gt;timeout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;setImmediate&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;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="s1"&gt;immediate&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="c1"&gt;// → immediate, then timeout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The one rule that keeps Node fast
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Never block the event loop.&lt;/strong&gt; A heavy CPU task (huge loop, sync crypto, giant JSON parse) freezes &lt;em&gt;everything&lt;/em&gt;, because it hogs the single thread. Offload it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;worker_threads&lt;/code&gt; for CPU-heavy work&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;cluster&lt;/code&gt; module to use all cores&lt;/li&gt;
&lt;li&gt;a queue/microservice for big jobs&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;One JS thread + the event loop = non-blocking I/O&lt;/li&gt;
&lt;li&gt;Microtasks (nextTick, Promises) run before the next phase&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setImmediate&lt;/code&gt; beats &lt;code&gt;setTimeout(0)&lt;/code&gt; inside I/O&lt;/li&gt;
&lt;li&gt;Don't block the loop with heavy CPU work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The event loop is one of the most common interview questions too — if you want the full set, I put together a &lt;strong&gt;64-question Node.js interview guide&lt;/strong&gt; here: &lt;a href="https://asbackendinstitute.com/blog/nodejs-interview-questions/top-60-nodejs-interview-questions" rel="noopener noreferrer"&gt;https://asbackendinstitute.com/blog/nodejs-interview-questions/top-60-nodejs-interview-questions&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I teach hands-on backend development (Node.js, Express, MongoDB, Redis) at &lt;a href="https://asbackendinstitute.com" rel="noopener noreferrer"&gt;AS Backend Institute&lt;/a&gt;. More practical guides like this if you're learning backend. 🚀&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>15 Node.js Interview Questions You Should Be Able to Answer (2026)</title>
      <dc:creator>Akash Gupta</dc:creator>
      <pubDate>Mon, 24 Aug 2026 19:35:15 +0000</pubDate>
      <link>https://dev.to/akashguptasky/15-nodejs-interview-questions-you-should-be-able-to-answer-2026-5aeg</link>
      <guid>https://dev.to/akashguptasky/15-nodejs-interview-questions-you-should-be-able-to-answer-2026-5aeg</guid>
      <description>&lt;p&gt;Prepping for a Node.js interview? Here are 15 questions that come up again and again — with short, to-the-point answers. If you can explain these clearly, you're in good shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basics
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. What is Node.js?&lt;/strong&gt;&lt;br&gt;
A runtime to run JavaScript outside the browser (built on V8). It's event-driven and non-blocking — great for I/O-heavy apps like APIs and real-time servers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Is Node.js single-threaded?&lt;/strong&gt;&lt;br&gt;
Your JS runs on one main thread, but Node offloads heavy I/O to libuv's background thread pool. So it feels single-threaded but uses multiple threads under the hood.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. CommonJS vs ES Modules?&lt;/strong&gt;&lt;br&gt;
CommonJS uses &lt;code&gt;require&lt;/code&gt;/&lt;code&gt;module.exports&lt;/code&gt; (synchronous, classic). ES Modules use &lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt; (modern standard, async, tree-shakeable). Enable ESM via &lt;code&gt;"type":"module"&lt;/code&gt; or &lt;code&gt;.mjs&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event loop &amp;amp; async
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;4. What is the event loop?&lt;/strong&gt;&lt;br&gt;
The mechanism that lets single-threaded Node handle many operations at once — it runs callbacks for completed async tasks (timers, I/O) when the call stack is empty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. setTimeout vs setImmediate?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;setImmediate&lt;/code&gt; runs in the "check" phase; &lt;code&gt;setTimeout(fn,0)&lt;/code&gt; in the timers phase. Inside an I/O callback, &lt;code&gt;setImmediate&lt;/code&gt; always fires first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. What is async/await?&lt;/strong&gt;&lt;br&gt;
Syntactic sugar over Promises so async code reads like sync code. An &lt;code&gt;async&lt;/code&gt; function returns a Promise; &lt;code&gt;await&lt;/code&gt; pauses until it settles. Handle errors with try/catch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Promise.all vs allSettled vs race vs any?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;all&lt;/code&gt;: rejects on first failure. &lt;code&gt;allSettled&lt;/code&gt;: waits for all, reports each. &lt;code&gt;race&lt;/code&gt;: first to settle wins. &lt;code&gt;any&lt;/code&gt;: first success wins, rejects only if all fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. How do you handle CPU-intensive tasks?&lt;/strong&gt;&lt;br&gt;
Offload them — &lt;code&gt;worker_threads&lt;/code&gt; for parallel CPU work, child processes, or the &lt;code&gt;cluster&lt;/code&gt; module to use all cores. Never block the single JS thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modules &amp;amp; core
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;9. What are streams?&lt;/strong&gt;&lt;br&gt;
They process data in chunks instead of loading it all into memory — ideal for large files/network. Types: Readable, Writable, Duplex, Transform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. How does require() caching work?&lt;/strong&gt;&lt;br&gt;
The first &lt;code&gt;require()&lt;/code&gt; runs the module and caches its exports. Later requires return the cache — so top-level module code runs only once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Express &amp;amp; REST
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;11. What is middleware?&lt;/strong&gt;&lt;br&gt;
A function with &lt;code&gt;(req, res, next)&lt;/code&gt; that runs during the request-response cycle. It can read/modify req/res, end the response, or call &lt;code&gt;next()&lt;/code&gt; to pass control on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. What are the key REST principles?&lt;/strong&gt;&lt;br&gt;
Resources identified by URLs (nouns), standard HTTP methods (verbs), stateless requests, and meaningful status codes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth &amp;amp; security
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;13. How does JWT auth work?&lt;/strong&gt;&lt;br&gt;
On login the server signs a token (header.payload.signature). The client sends it on each request; the server verifies the signature. The payload is only Base64-encoded — never put secrets in it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;14. How should you store passwords?&lt;/strong&gt;&lt;br&gt;
Never plain text. Hash with a slow, salted algorithm like bcrypt, and compare with &lt;code&gt;bcrypt.compare&lt;/code&gt; on login — you never decrypt the stored hash.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;15. How do you scale a Node app?&lt;/strong&gt;&lt;br&gt;
Use the &lt;code&gt;cluster&lt;/code&gt; module (or PM2) to use all CPU cores, cache with Redis, add DB indexes, avoid blocking the event loop, and paginate large responses.&lt;/p&gt;




&lt;p&gt;Want the full set? I wrote a &lt;strong&gt;complete 64-question guide (beginner → advanced, with English/Hinglish)&lt;/strong&gt; here:&lt;br&gt;
👉 &lt;a href="https://asbackendinstitute.com/blog/nodejs-interview-questions/top-60-nodejs-interview-questions" rel="noopener noreferrer"&gt;https://asbackendinstitute.com/blog/nodejs-interview-questions/top-60-nodejs-interview-questions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What question do you always get asked in Node interviews? Drop it below 👇&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>interview</category>
    </item>
    <item>
      <title>JWT Authentication in Node.js: A Practical Guide (with Express)</title>
      <dc:creator>Akash Gupta</dc:creator>
      <pubDate>Mon, 24 Aug 2026 12:42:21 +0000</pubDate>
      <link>https://dev.to/akashguptasky/jwt-authentication-in-nodejs-a-practical-guide-with-express-2341</link>
      <guid>https://dev.to/akashguptasky/jwt-authentication-in-nodejs-a-practical-guide-with-express-2341</guid>
      <description>&lt;p&gt;Ever logged into an app, closed the tab, come back, and you're &lt;em&gt;still&lt;/em&gt; logged in — no password needed? That's almost always &lt;strong&gt;JWT&lt;/strong&gt; doing its job behind the scenes.&lt;/p&gt;

&lt;p&gt;JWT (JSON Web Token) is one of the most common ways to handle authentication in modern backends. But a lot of developers use it without really understanding what's happening — and that's exactly where security bugs sneak in.&lt;/p&gt;

&lt;p&gt;Let's fix that. By the end of this post you'll know what a JWT actually is, how to use it in a Node.js + Express app, and the mistakes that quietly break real apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a JWT, really?
&lt;/h2&gt;

&lt;p&gt;A JWT is just a &lt;strong&gt;string with three parts&lt;/strong&gt;, separated by dots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xxxxx.yyyyy.zzzzz
   │      │      │
 header payload signature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Header&lt;/strong&gt; — says which algorithm signed the token (e.g. &lt;code&gt;HS256&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payload&lt;/strong&gt; — the actual data (like &lt;code&gt;userId&lt;/code&gt;, &lt;code&gt;role&lt;/code&gt;, and an expiry time). This is &lt;strong&gt;not encrypted&lt;/strong&gt; — it's just Base64-encoded. Anyone can read it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signature&lt;/strong&gt; — a cryptographic stamp created using a &lt;strong&gt;secret&lt;/strong&gt; only your server knows. This is what stops people from faking tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want to see this for yourself? Paste any token into a free &lt;a href="https://asbackendinstitute.com/tools/jwt-decoder" rel="noopener noreferrer"&gt;JWT decoder&lt;/a&gt; and you'll instantly see the header and payload. Notice you can read everything &lt;em&gt;without&lt;/em&gt; the secret — that's the key lesson: &lt;strong&gt;never put passwords or sensitive data in a JWT payload.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a token (login)
&lt;/h2&gt;

&lt;p&gt;Install the library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;jsonwebtoken
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a user logs in successfully, sign a token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// On successful login:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&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="c1"&gt;// payload&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;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                    &lt;span class="c1"&gt;// secret (keep it in .env!)&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;7d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;                        &lt;span class="c1"&gt;// auto-expiry&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things to notice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep the payload &lt;strong&gt;small&lt;/strong&gt; — just an id and role, not the whole user object.&lt;/li&gt;
&lt;li&gt;The secret lives in an environment variable, &lt;strong&gt;never&lt;/strong&gt; hardcoded.&lt;/li&gt;
&lt;li&gt;Always set &lt;code&gt;expiresIn&lt;/code&gt;. A token that never expires is a token that can be stolen forever.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Verifying a token (protecting routes)
&lt;/h2&gt;

&lt;p&gt;Now create a middleware that checks the token on every protected request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;auth&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;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="dl"&gt;''&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No token provided&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoded&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;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;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;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt;          &lt;span class="c1"&gt;// { userId, role, iat, exp }&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;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid or expired token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use it on any route you want to protect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&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;That's the whole core loop: &lt;strong&gt;sign on login, verify on every request.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The mistakes that break real apps
&lt;/h2&gt;

&lt;p&gt;These are the ones I see again and again:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Trusting the payload without verifying.&lt;/strong&gt; Decoding a token (reading it) is &lt;em&gt;not&lt;/em&gt; the same as verifying it. Always use &lt;code&gt;jwt.verify()&lt;/code&gt;, never just decode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A weak or leaked secret.&lt;/strong&gt; If your secret is &lt;code&gt;secret123&lt;/code&gt; or committed to GitHub, anyone can forge valid tokens. Use a long random string.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No expiry.&lt;/strong&gt; Always set &lt;code&gt;expiresIn&lt;/code&gt;. Pair short-lived access tokens with a longer refresh token for a better experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storing the token in &lt;code&gt;localStorage&lt;/code&gt; carelessly.&lt;/strong&gt; It's vulnerable to XSS. For sensitive apps, an &lt;code&gt;httpOnly&lt;/code&gt; cookie is safer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Putting secrets in the payload.&lt;/strong&gt; Remember — the payload is readable by anyone. No passwords, no card numbers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Debugging tip
&lt;/h2&gt;

&lt;p&gt;When something "just doesn't work," the fastest fix is to actually &lt;em&gt;look&lt;/em&gt; at the token. Drop it into a &lt;a href="https://asbackendinstitute.com/tools/jwt-decoder" rel="noopener noreferrer"&gt;JWT decoder&lt;/a&gt; and check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the &lt;code&gt;exp&lt;/code&gt; (expiry) in the past? → token expired.&lt;/li&gt;
&lt;li&gt;Is the payload what you expect? → maybe you signed the wrong data.&lt;/li&gt;
&lt;li&gt;Wrong &lt;code&gt;alg&lt;/code&gt; in the header? → algorithm mismatch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;90% of JWT bugs become obvious the moment you see the decoded token.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;JWT isn't magic — it's a signed string that says "this user is who they claim to be, and here's proof my server made it." Get the basics right (small payload, strong secret, always expire, always verify) and you've covered most of what breaks in production.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I teach hands-on backend development (Node.js, Express, MongoDB, Redis) at &lt;a href="https://asbackendinstitute.com" rel="noopener noreferrer"&gt;AS Backend Institute&lt;/a&gt;. If you're learning backend and want more practical guides like this, come say hi. 🚀&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>node</category>
      <category>security</category>
    </item>
    <item>
      <title>I built a full backend-learning platform solo — here's what I shipped (and what broke along the way)</title>
      <dc:creator>Akash Gupta</dc:creator>
      <pubDate>Sat, 08 Aug 2026 22:15:45 +0000</pubDate>
      <link>https://dev.to/akashguptasky/i-built-a-full-backend-learning-platform-solo-heres-what-i-shipped-and-what-broke-along-the-way-990</link>
      <guid>https://dev.to/akashguptasky/i-built-a-full-backend-learning-platform-solo-heres-what-i-shipped-and-what-broke-along-the-way-990</guid>
      <description>&lt;p&gt;A few months ago I got tired of the same problem: you finish a "backend course," feel great for a day, then realize you still can't build anything real or pass an interview.&lt;/p&gt;

&lt;p&gt;So I started building the thing I wish I'd had when I began. Today it's finally live: &lt;strong&gt;&lt;a href="https://asbackendinstitute.com" rel="noopener noreferrer"&gt;https://asbackendinstitute.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Posting it here because dev.to is where I learned a ton — I'd genuinely love your feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;Most resources hand you videos and call it a day. The gap between "I watched a tutorial" and "I can actually build and get hired" is where people give up. I wanted the whole thing to be hands-on and job-focused.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's inside
&lt;/h2&gt;

&lt;p&gt;Instead of just videos, I tried to make everything practical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js &amp;amp; Socket.io courses&lt;/strong&gt; — from scratch, with an English/Hinglish toggle (India-first audience)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A 24-topic roadmap&lt;/strong&gt; with progress tracking, so you always know what's next&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI mock interviews&lt;/strong&gt; — two interviewer personas that actually grill you and score you&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DSA practice&lt;/strong&gt; with a "select any line → AI explains it" helper&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live classes&lt;/strong&gt; with recordings + AI-generated notes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-browser dev stack&lt;/strong&gt; — run MongoDB and code without any local setup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A "Backend Ready" certificate&lt;/strong&gt; you can only earn by proving skills (no participation trophies)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resume + portfolio builder&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Installable as a &lt;strong&gt;PWA&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The tech (for the curious)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; React + Vite → Netlify&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Node.js + Express (ESM), MongoDB + Mongoose → Render&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Realtime:&lt;/strong&gt; Socket.io for live classes/chat, WebRTC (mesh) for video rooms &amp;amp; 1:1 calls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PWA:&lt;/strong&gt; service worker for install + web push notifications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI:&lt;/strong&gt; Anthropic / Gemini / Groq for the interview, explainers and notes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A few things I learned (the hard way)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WebRTC across mobile networks is brutal.&lt;/strong&gt; STUN alone isn't enough — symmetric NATs (hello, mobile data) need a TURN server. I spent way too long debugging "why won't the remote video show up."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache invalidation is genuinely one of the hard problems.&lt;/strong&gt; A stale server cache + client cache had me chasing "why isn't my new logo showing" far longer than I'd like to admit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shipping beats perfect.&lt;/strong&gt; It's not finished — but it's real, and it's out there.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  It's live — feedback welcome 🙏
&lt;/h2&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://asbackendinstitute.com" rel="noopener noreferrer"&gt;https://asbackendinstitute.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're learning backend (or teaching it), I'd love to hear what you'd want added. I'm actively building on it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>beginners</category>
      <category>showdev</category>
    </item>
    <item>
      <title>dotenv-audit v1.1.0 — now with .env.example auto-sync</title>
      <dc:creator>Akash Gupta</dc:creator>
      <pubDate>Tue, 07 Apr 2026 19:09:09 +0000</pubDate>
      <link>https://dev.to/akashguptasky/dotenv-audit-v110-now-with-envexample-auto-sync-18ei</link>
      <guid>https://dev.to/akashguptasky/dotenv-audit-v110-now-with-envexample-auto-sync-18ei</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is a follow-up to my previous article: &lt;a href="https://dev.to/akashguptasky/i-built-a-cli-tool-that-auto-detects-missing-environment-variables-no-schema-needed-gpn"&gt;I built a CLI tool that auto-detects missing environment variables — no schema needed&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quick update on dotenv-audit — the CLI tool that scans your code and finds missing environment variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's new in v1.1.0
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;sync&lt;/code&gt; command — keep .env.example in sync with your code
&lt;/h3&gt;

&lt;p&gt;The most common problem with &lt;code&gt;.env.example&lt;/code&gt; files? They go outdated. Someone adds a new &lt;code&gt;process.env.STRIPE_KEY&lt;/code&gt; in code but forgets to update &lt;code&gt;.env.example&lt;/code&gt;. New developers clone the repo, miss the variable, and waste time debugging.&lt;/p&gt;

&lt;p&gt;Now just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx dotenv-audit &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;It will:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Scan your code for every process.env usage&lt;br&gt;
Compare with your existing .env.example&lt;br&gt;
Add missing variables with smart placeholder values&lt;br&gt;
Warn about unused variables that should be removed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env.example&lt;/span&gt;
&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3000
&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;OLD_UNUSED_VAR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;something
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After running npx dotenv-audit sync:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  dotenv-audit &lt;span class="nb"&gt;sync
  &lt;/span&gt;Scanned 12 files

  + 2 variable&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; missing from .env.example:
    + API_KEY        app.js:3
    + STRIPE_KEY     payments.ts:22

  - 1 variable&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; .env.example but not used &lt;span class="k"&gt;in &lt;/span&gt;code:
    - OLD_UNUSED_VAR

  ✓ Added 2 variable&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; to .env.example
  &lt;span class="o"&gt;!&lt;/span&gt; 1 unused variable&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; found — review and remove manually
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Your .env.example now has:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3000
&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;OLD_UNUSED_VAR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;something

&lt;span class="c"&gt;# ── Added by dotenv-audit sync ──────────────&lt;/span&gt;
&lt;span class="c"&gt;# Other&lt;/span&gt;
&lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_api_key_here

&lt;span class="c"&gt;# Stripe&lt;/span&gt;
&lt;span class="nv"&gt;STRIPE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk_test_your_stripe_secret_key_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Local .env file reading (bug fix in v1.0.3)
Previously the tool only checked process.env at runtime — so if you had variables in your .env file, they were still showing as "missing". Fixed. Now it reads .env and .env.local before validating.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;All commands&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx dotenv-audit              &lt;span class="c"&gt;# Scan and show missing vars&lt;/span&gt;
npx dotenv-audit &lt;span class="nt"&gt;--ask&lt;/span&gt;        &lt;span class="c"&gt;# Interactive mode (generate .env + ENV_SETUP.md)&lt;/span&gt;
npx dotenv-audit &lt;span class="nb"&gt;sync&lt;/span&gt;         &lt;span class="c"&gt;# Sync .env.example with code&lt;/span&gt;
npx dotenv-audit audit        &lt;span class="c"&gt;# List all detected variables&lt;/span&gt;
npx dotenv-audit gen          &lt;span class="c"&gt;# Generate .env.example from scratch&lt;/span&gt;
npx dotenv-audit &lt;span class="nt"&gt;--json&lt;/span&gt; &lt;span class="nt"&gt;--ci&lt;/span&gt;  &lt;span class="c"&gt;# CI mode with JSON output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;br&gt;
npx dotenv-audit sync&lt;br&gt;
npm: &lt;a href="https://www.npmjs.com/package/dotenv-audit" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/dotenv-audit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;400+ downloads in the first 2 days. Would love your feedback — what would you want next?&lt;/p&gt;




&lt;p&gt;Thanks for reading! If you missed the first article, check it out here: &lt;a href="https://dev.to/akashguptasky/i-built-a-cli-tool-that-auto-detects-missing-environment-variables-no-schema-needed-gpn"&gt;How I built dotenv-audit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you find it useful, drop a ❤️ and share it with your team!&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>development</category>
    </item>
    <item>
      <title>I built a CLI tool that auto-detects missing environment variables — no schema needed</title>
      <dc:creator>Akash Gupta</dc:creator>
      <pubDate>Sun, 05 Apr 2026 19:35:26 +0000</pubDate>
      <link>https://dev.to/akashguptasky/i-built-a-cli-tool-that-auto-detects-missing-environment-variables-no-schema-needed-gpn</link>
      <guid>https://dev.to/akashguptasky/i-built-a-cli-tool-that-auto-detects-missing-environment-variables-no-schema-needed-gpn</guid>
      <description>&lt;p&gt;Every Node.js developer has faced this at least once:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;App crashes in production.&lt;br&gt;
"Cannot read property of undefined."&lt;br&gt;
2 hours of debugging later — someone forgot to set DATABASE_URL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I got tired of this. So I built &lt;strong&gt;dotenv-audit&lt;/strong&gt; — a CLI tool that scans your actual code, finds every &lt;code&gt;process.env&lt;/code&gt; usage, and tells you exactly what's missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Existing Tools
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;dotenv&lt;/strong&gt; → loads &lt;code&gt;.env&lt;/code&gt; file. Doesn't validate anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;envalid&lt;/strong&gt; → validates, but you have to write a schema manually:&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;// With envalid - you write this for EVERY variable&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cleanEnv&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="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;port&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;REDIS_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="c1"&gt;// ... 20 more lines&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem? You already wrote &lt;code&gt;process .env.DATABASE_URL&lt;/code&gt; in your code. Why write it again in a schema?&lt;/p&gt;

&lt;p&gt;The Solution&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;npx&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;audit&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;ask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. One command. It:&lt;/p&gt;

&lt;p&gt;Scans your .js, .ts, .jsx, .tsx, .vue, .svelte files&lt;br&gt;
Finds every &lt;code&gt;process.env.XXXX&lt;/code&gt; automatically&lt;br&gt;
Shows what's missing with exact file locations&lt;br&gt;
Generates a &lt;code&gt;.env&lt;/code&gt; file with smart placeholder values&lt;br&gt;
Output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;audit&lt;/span&gt;  &lt;span class="nx"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;
  &lt;span class="err"&gt;──────────────────────────────────────────&lt;/span&gt;
  &lt;span class="nx"&gt;Scanned&lt;/span&gt; &lt;span class="mi"&gt;47&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="err"&gt;·&lt;/span&gt; &lt;span class="nx"&gt;Found&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;

  &lt;span class="err"&gt;✗&lt;/span&gt; &lt;span class="nc"&gt;MISSING &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="err"&gt;✗&lt;/span&gt; &lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;
      &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;

    &lt;span class="err"&gt;✗&lt;/span&gt; &lt;span class="nx"&gt;JWT_SECRET&lt;/span&gt;
      &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;

    &lt;span class="err"&gt;✗&lt;/span&gt; &lt;span class="nx"&gt;STRIPE_KEY&lt;/span&gt;
      &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;payments&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;

  &lt;span class="err"&gt;⚠&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;verbose&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;see&lt;/span&gt; &lt;span class="nx"&gt;details&lt;/span&gt;

  &lt;span class="err"&gt;✓&lt;/span&gt; &lt;span class="nc"&gt;SET &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="err"&gt;──────────────────────────────────────────&lt;/span&gt;
  &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="nx"&gt;missing&lt;/span&gt; &lt;span class="err"&gt;·&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Smart &lt;code&gt;.env&lt;/code&gt; Generation&lt;br&gt;
When you run --ask mode, it asks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Generate&lt;/span&gt; &lt;span class="nx"&gt;ENV_SETUP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;md&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;missing&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;yes&lt;/span&gt;
&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Create&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;missing&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;yes&lt;/span&gt;
&lt;span class="nx"&gt;And&lt;/span&gt; &lt;span class="nx"&gt;generates&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;aware&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;


&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="err"&gt;──&lt;/span&gt; &lt;span class="nx"&gt;Database&lt;/span&gt; &lt;span class="err"&gt;────────────────────────────────&lt;/span&gt;
&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;mongodb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:27017/your_database_name&lt;/span&gt;
&lt;span class="nx"&gt;REDIS_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;localhost&lt;/span&gt;
&lt;span class="nx"&gt;REDIS_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6379&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="err"&gt;──&lt;/span&gt; &lt;span class="nx"&gt;Authentication&lt;/span&gt; &lt;span class="err"&gt;──────────────────────────&lt;/span&gt;
&lt;span class="nx"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;your_jwt_secret_key_min_32_chars_long&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="err"&gt;──&lt;/span&gt; &lt;span class="nx"&gt;Stripe&lt;/span&gt; &lt;span class="err"&gt;──────────────────────────────────&lt;/span&gt;
&lt;span class="nx"&gt;STRIPE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;sk_test_your_stripe_secret_key_here&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="err"&gt;──&lt;/span&gt; &lt;span class="nx"&gt;AI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;LLM&lt;/span&gt; &lt;span class="err"&gt;────────────────────────────────&lt;/span&gt;
&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;sk&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;your_openai_api_key_here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It even reads your &lt;code&gt;package.json&lt;/code&gt; — if you use &lt;code&gt;mongoose&lt;/code&gt;, it gives &lt;code&gt;mongodb://&lt;/code&gt; URLs. If you use &lt;code&gt;pg&lt;/code&gt;, it gives &lt;code&gt;postgresql://&lt;/code&gt; URLs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detection Patterns&lt;/strong&gt;&lt;br&gt;
It catches all the ways developers access env variables:&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;// All detected:&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;DATABASE_URL&lt;/span&gt;              &lt;span class="c1"&gt;// dot access&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;                &lt;span class="c1"&gt;// bracket access&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;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HOST&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;    &lt;span class="c1"&gt;// destructuring&lt;/span&gt;
&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;              &lt;span class="c1"&gt;// defaults (shown as warning)&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&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;VITE_API_URL&lt;/span&gt;         &lt;span class="c1"&gt;// Vite&lt;/span&gt;

&lt;span class="c1"&gt;// Smart filtering:&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&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;DEV&lt;/span&gt;                   &lt;span class="c1"&gt;// SKIPPED (Vite built-in)&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&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;MODE&lt;/span&gt;                  &lt;span class="c1"&gt;// SKIPPED (Vite built-in)&lt;/span&gt;
&lt;span class="c1"&gt;// process.env.COMMENTED              // SKIPPED (in comments)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Monorepo Support&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have a monorepo (pnpm workspaces, lerna, turbo), it auto-detects services and creates separate .env files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Create&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="nx"&gt;inside&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt; &lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="nx"&gt;folder&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;yes&lt;/span&gt;

  &lt;span class="err"&gt;✓&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;          &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;
  &lt;span class="err"&gt;✓&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;       &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;
  &lt;span class="err"&gt;✓&lt;/span&gt; &lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;

  &lt;span class="err"&gt;✓&lt;/span&gt; &lt;span class="nx"&gt;Done&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="nx"&gt;processed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No more dumping all variables into one file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use in CI/CD&lt;/strong&gt;&lt;br&gt;
Add this to your GitHub Actions:&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="o"&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;Validate&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="nx"&gt;vars&lt;/span&gt;
  &lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;audit&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;ci&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If any required variable is missing, the pipeline fails — before your app does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Comparison&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;Feature&lt;/th&gt;
&lt;th&gt;dotenv&lt;/th&gt;
&lt;th&gt;envalid&lt;/th&gt;
&lt;th&gt;dotenv-audit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Auto-detect from code&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero schema needed&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generate &lt;code&gt;.env&lt;/code&gt; file&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database auto-detect&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monorepo support&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero dependencies&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Try It&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;audit&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;ask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/dotenv-audit" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/dotenv-audit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is my first npm package. I'd genuinely love feedback — what features would make this more useful for your workflow?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;a href="https://dev.to/akashguptasky/dotenv-audit-v110-now-with-envexample-auto-sync-18ei"&gt;v1.1.0 released with .env.example auto-sync →&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
