<?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: Maulik Solanki</title>
    <description>The latest articles on DEV Community by Maulik Solanki (@maulik_solanki_6660abf902).</description>
    <link>https://dev.to/maulik_solanki_6660abf902</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3584494%2Fe42f98b4-ae4b-4e23-911f-28d661c24d0d.png</url>
      <title>DEV Community: Maulik Solanki</title>
      <link>https://dev.to/maulik_solanki_6660abf902</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maulik_solanki_6660abf902"/>
    <language>en</language>
    <item>
      <title>I built a simple tool to stop wasting time on repetitive file tasks</title>
      <dc:creator>Maulik Solanki</dc:creator>
      <pubDate>Thu, 09 Apr 2026 10:16:05 +0000</pubDate>
      <link>https://dev.to/maulik_solanki_6660abf902/i-built-a-simple-tool-to-stop-wasting-time-on-repetitive-file-tasks-1jig</link>
      <guid>https://dev.to/maulik_solanki_6660abf902/i-built-a-simple-tool-to-stop-wasting-time-on-repetitive-file-tasks-1jig</guid>
      <description>&lt;p&gt;I was constantly switching between different tools just to do basic things —&lt;br&gt;
merge PDFs, compress images, convert files, generate QR codes, etc.&lt;/p&gt;

&lt;p&gt;It felt unnecessary.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;PixelTrim&lt;/strong&gt; — a lightweight, no-login toolkit that handles these everyday tasks in one place.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it can do:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Merge &amp;amp; convert PDFs&lt;/li&gt;
&lt;li&gt;Compress, resize, and edit images&lt;/li&gt;
&lt;li&gt;Remove image backgrounds&lt;/li&gt;
&lt;li&gt;Extract text from images (OCR)&lt;/li&gt;
&lt;li&gt;Generate QR codes&lt;/li&gt;
&lt;li&gt;Word counter, font generator, and more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The focus was simple:&lt;br&gt;
→ fast&lt;br&gt;
→ minimal&lt;br&gt;
→ no friction&lt;/p&gt;

&lt;p&gt;No signups, no clutter — just open and use.&lt;/p&gt;

&lt;p&gt;🔗 Try it here: &lt;a href="https://pixeltrim.vercel.app/" rel="noopener noreferrer"&gt;https://pixeltrim.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m still improving it, so I’d really appreciate feedback —&lt;br&gt;
What other tools would you want in something like this?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>productivity</category>
      <category>react</category>
    </item>
    <item>
      <title>I Dockerized My MERN App for Production in 2026 — Here's Everything I Wish Someone Had Told Me</title>
      <dc:creator>Maulik Solanki</dc:creator>
      <pubDate>Sat, 21 Mar 2026 10:27:17 +0000</pubDate>
      <link>https://dev.to/maulik_solanki_6660abf902/i-dockerized-my-mern-app-for-production-in-2026-heres-everything-i-wish-someone-had-told-me-2074</link>
      <guid>https://dev.to/maulik_solanki_6660abf902/i-dockerized-my-mern-app-for-production-in-2026-heres-everything-i-wish-someone-had-told-me-2074</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I spent 3 days trying to Dockerize my MERN app "the right way." It crashed on deployment, leaked env vars, had a 1.2GB image, and React couldn't talk to Express. This post is the complete story + the final setup that works. Copy-paste ready.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧠 Why I even bothered with Docker
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaydgh0f93b0f64g5k3s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaydgh0f93b0f64g5k3s.jpg" alt="Docker image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was a Friday evening. My MERN app worked perfectly on my machine.&lt;/p&gt;

&lt;p&gt;I pushed to the VPS. It broke immediately.&lt;/p&gt;

&lt;p&gt;Node version mismatch. Then MongoDB connection string issues. Then React's &lt;code&gt;VITE_API_URL&lt;/code&gt; was pointing to &lt;code&gt;localhost&lt;/code&gt; in production. I spent 6 hours fixing things that had nothing to do with my actual app.&lt;/p&gt;

&lt;p&gt;That Sunday, I decided: &lt;strong&gt;never again.&lt;/strong&gt; Docker was the answer — one environment everywhere, no surprises on deployment.&lt;/p&gt;

&lt;p&gt;What followed was 3 days of learning, breaking things, and eventually getting it right. Here's the complete story.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ What we're building
&lt;/h2&gt;

&lt;p&gt;A production-ready Docker setup for a full MERN stack app with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB&lt;/strong&gt; — running in a container (with a volume for data persistence)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Express + Node.js&lt;/strong&gt; — the API server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React (Vite)&lt;/strong&gt; — the frontend, built and served via Nginx&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docker-compose&lt;/strong&gt; — orchestrating all three together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what the final folder structure looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-mern-app/
├── client/                  # React + Vite frontend
│   ├── src/
│   ├── Dockerfile
│   └── nginx.conf
├── server/                  # Express + Node backend
│   ├── src/
│   ├── Dockerfile
│   └── .dockerignore
├── docker-compose.yml
├── docker-compose.prod.yml
└── .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💥 Mistake #1 — My first Dockerfile was a disaster
&lt;/h2&gt;

&lt;p&gt;My first attempt at a server Dockerfile looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# ❌ my first (terrible) attempt&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:latest&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "src/index.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three problems with this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;node:latest&lt;/code&gt; — this pulls a different version every time you build. Your dev build and prod build can use different Node versions silently.&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;.dockerignore&lt;/code&gt; — I was copying &lt;code&gt;node_modules&lt;/code&gt; (800MB+) into the image and then overwriting it with &lt;code&gt;npm install&lt;/code&gt;. Wasteful and slow.&lt;/li&gt;
&lt;li&gt;Single stage — the final image contained dev dependencies, source maps, everything. My image was &lt;strong&gt;1.2GB&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's what I replaced it with:&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ The Server Dockerfile — multi-stage, lean, production-ready
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# server/Dockerfile&lt;/span&gt;

&lt;span class="c"&gt;# ---- Stage 1: Install dependencies ----&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;deps&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production

&lt;span class="c"&gt;# ---- Stage 2: Production image ----&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;runner&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Create non-root user for security&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-S&lt;/span&gt; appgroup &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser &lt;span class="nt"&gt;-S&lt;/span&gt; appuser &lt;span class="nt"&gt;-G&lt;/span&gt; appgroup

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=deps /app/node_modules ./node_modules&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src/ ./src/&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json ./&lt;/span&gt;

&lt;span class="c"&gt;# Switch to non-root user&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; appuser&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 5000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "src/index.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key decisions here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;node:20-alpine&lt;/code&gt; — pinned version, Alpine Linux base = tiny image (~180MB vs 1.2GB)&lt;/li&gt;
&lt;li&gt;Multi-stage build — only production deps and source code end up in the final image&lt;/li&gt;
&lt;li&gt;Non-root user — running as &lt;code&gt;root&lt;/code&gt; inside a container is a security risk. This is the 2026 standard.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm ci&lt;/code&gt; instead of &lt;code&gt;npm install&lt;/code&gt; — faster, deterministic, respects &lt;code&gt;package-lock.json&lt;/code&gt; exactly&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔥 Mistake #2 — React was calling &lt;code&gt;localhost&lt;/code&gt; in production
&lt;/h2&gt;

&lt;p&gt;This one genuinely confused me for half a day.&lt;/p&gt;

&lt;p&gt;My React code had this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ hardcoded — breaks in every environment except local&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:5000/api/products&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;Even after I "fixed" it with an env variable:&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="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="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/products`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...it still broke. Because &lt;code&gt;VITE_API_URL&lt;/code&gt; was empty in the Docker build. Vite bakes env vars &lt;strong&gt;at build time&lt;/strong&gt;, not runtime. The container didn't have access to my &lt;code&gt;.env&lt;/code&gt; file during the build stage.&lt;/p&gt;

&lt;p&gt;The fix was passing the build arg explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# client/Dockerfile&lt;/span&gt;

&lt;span class="c"&gt;# ---- Stage 1: Build React app ----&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Accept build arg&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; VITE_API_URL&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; VITE_API_URL=$VITE_API_URL&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# ---- Stage 2: Serve with Nginx ----&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;nginx:alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;runner&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/dist /usr/share/nginx/html&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; nginx.conf /etc/nginx/conf.d/default.conf&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["nginx", "-g", "daemon off;"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in &lt;code&gt;docker-compose.yml&lt;/code&gt;, pass the arg at build time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./client&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${VITE_API_URL}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🌐 The Nginx config — the piece everyone forgets
&lt;/h2&gt;

&lt;p&gt;React is a SPA. If you navigate to &lt;code&gt;/dashboard&lt;/code&gt; and refresh, Nginx tries to find a file called &lt;code&gt;dashboard&lt;/code&gt; — it doesn't exist, and you get a 404.&lt;/p&gt;

&lt;p&gt;This tiny &lt;code&gt;nginx.conf&lt;/code&gt; fixes that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# client/nginx.conf&lt;/span&gt;
&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/usr/share/nginx/html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# ✅ This is the critical line — sends all routes to React&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="n"&gt;/index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Proxy API calls to backend — no CORS issues&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/api&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://server:5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Upgrade&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Connection&lt;/span&gt; &lt;span class="s"&gt;'upgrade'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_cache_bypass&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;/api&lt;/code&gt; proxy block is the real win here. React calls &lt;code&gt;/api/products&lt;/code&gt; — Nginx forwards it to the Express container internally. No CORS headers needed. No &lt;code&gt;http://localhost:5000&lt;/code&gt; in your React code.&lt;/p&gt;




&lt;h2&gt;
  
  
  🐳 The docker-compose.yml — full orchestration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.yml (development)&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.9'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mongo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo:7&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mern_mongo&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${MONGO_ROOT_USER}&lt;/span&gt;
      &lt;span class="na"&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${MONGO_ROOT_PASSWORD}&lt;/span&gt;
      &lt;span class="na"&gt;MONGO_INITDB_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${MONGO_DB_NAME}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mongo_data:/data/db&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;27017:27017"&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mern_network&lt;/span&gt;

  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./server&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mern_server&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;development&lt;/span&gt;
      &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
      &lt;span class="na"&gt;MONGO_URI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongodb://${MONGO_ROOT_USER}:${MONGO_ROOT_PASSWORD}@mongo:27017/${MONGO_DB_NAME}?authSource=admin&lt;/span&gt;
      &lt;span class="na"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${JWT_SECRET}&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5000:5000"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mern_network&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./server/src:/app/src&lt;/span&gt;   &lt;span class="c1"&gt;# hot reload in dev&lt;/span&gt;

  &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./client&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${VITE_API_URL}&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mern_client&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;server&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mern_network&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mongo_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mern_network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth explaining:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mongo:27017&lt;/code&gt; — inside Docker, containers talk to each other by &lt;strong&gt;service name&lt;/strong&gt;, not &lt;code&gt;localhost&lt;/code&gt;. Your Express &lt;code&gt;MONGO_URI&lt;/code&gt; should use &lt;code&gt;mongo&lt;/code&gt; (the service name), not &lt;code&gt;localhost&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;depends_on&lt;/code&gt; — ensures MongoDB starts before Express. Note: it doesn't wait for Mongo to be &lt;em&gt;ready&lt;/em&gt;, just &lt;em&gt;started&lt;/em&gt;. More on that below.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mongo_data&lt;/code&gt; volume — your database persists across container restarts. Without this, every &lt;code&gt;docker-compose down&lt;/code&gt; wipes your data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mern_network&lt;/code&gt; — all services share a private network. Nothing is exposed to the internet except what you explicitly map with &lt;code&gt;ports&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔐 The .env file — never commit this
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env — add this to .gitignore immediately&lt;/span&gt;

&lt;span class="nv"&gt;MONGO_ROOT_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;maulik
&lt;span class="nv"&gt;MONGO_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;supersecretpassword123
&lt;span class="nv"&gt;MONGO_DB_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mernapp

&lt;span class="nv"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-very-long-random-jwt-secret-here

&lt;span class="nv"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .gitignore&lt;/span&gt;
.env
.env.&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;.env.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always commit a &lt;code&gt;.env.example&lt;/code&gt; with placeholder values so teammates know what variables are needed — but never the actual &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  💥 Mistake #3 — MongoDB wasn't ready when Express started
&lt;/h2&gt;

&lt;p&gt;Even with &lt;code&gt;depends_on: mongo&lt;/code&gt;, Express would start and immediately try to connect to MongoDB — which was still initializing. Result: crash.&lt;/p&gt;

&lt;p&gt;The fix is a retry loop in your Express server:&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;// server/src/db.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongoose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connectDB&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;retries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;retries&lt;/span&gt;&lt;span class="p"&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&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="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;✅ MongoDB connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="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="nx"&gt;retries&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`MongoDB not ready — retrying... (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; attempts left)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;❌ MongoDB connection failed after all retries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// Wait 5 seconds before retrying&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&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="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// server/src/index.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connectDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;span class="nf"&gt;connectDB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// handles its own retries&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;express&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="c1"&gt;// ... your routes&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;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;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`🚀 Server running on 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;5000&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🚀 The production docker-compose override
&lt;/h2&gt;

&lt;p&gt;For production, you don't want source volume mounts, you want smaller images, and you want proper restart policies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.prod.yml&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.9'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./server&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;runner&lt;/span&gt;         &lt;span class="c1"&gt;# use the production stage&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;              &lt;span class="c1"&gt;# no source mounts in prod&lt;/span&gt;

  &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./client&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;runner&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://yourdomain.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy with:&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;# Development&lt;/span&gt;
docker-compose up &lt;span class="nt"&gt;--build&lt;/span&gt;

&lt;span class="c"&gt;# Production&lt;/span&gt;
docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.prod.yml up &lt;span class="nt"&gt;--build&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Before vs after — the numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before Docker&lt;/th&gt;
&lt;th&gt;After Docker&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup time on new machine&lt;/td&gt;
&lt;td&gt;~45 minutes&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docker-compose up&lt;/code&gt; — 3 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Works on my machine" issues&lt;/td&gt;
&lt;td&gt;Every deployment&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image size (server)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;187MB (was 1.2GB before multi-stage)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MongoDB data loss on restart&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No (volume)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CORS issues&lt;/td&gt;
&lt;td&gt;Constant&lt;/td&gt;
&lt;td&gt;Gone (Nginx proxy)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Env var leaks&lt;/td&gt;
&lt;td&gt;Possible&lt;/td&gt;
&lt;td&gt;Contained&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🛠️ The .dockerignore files — don't skip these
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server/.dockerignore&lt;/span&gt;
node_modules
npm-debug.log
.env
.env.&lt;span class="k"&gt;*&lt;/span&gt;
.git
.gitignore
README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client/.dockerignore&lt;/span&gt;
node_modules
npm-debug.log
dist
.env
.env.&lt;span class="k"&gt;*&lt;/span&gt;
.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without &lt;code&gt;.dockerignore&lt;/code&gt;, Docker copies &lt;code&gt;node_modules&lt;/code&gt; into the build context — even though you don't need them. This makes builds painfully slow.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Quick commands to know
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start everything&lt;/span&gt;
docker-compose up &lt;span class="nt"&gt;--build&lt;/span&gt;

&lt;span class="c"&gt;# Start in background&lt;/span&gt;
docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--build&lt;/span&gt;

&lt;span class="c"&gt;# View logs&lt;/span&gt;
docker-compose logs &lt;span class="nt"&gt;-f&lt;/span&gt; server
docker-compose logs &lt;span class="nt"&gt;-f&lt;/span&gt; client

&lt;span class="c"&gt;# Stop everything (keeps volumes)&lt;/span&gt;
docker-compose down

&lt;span class="c"&gt;# Stop + wipe database volume (careful!)&lt;/span&gt;
docker-compose down &lt;span class="nt"&gt;-v&lt;/span&gt;

&lt;span class="c"&gt;# Rebuild one service only&lt;/span&gt;
docker-compose up &lt;span class="nt"&gt;--build&lt;/span&gt; server

&lt;span class="c"&gt;# Get a shell inside a running container&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; mern_server sh
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; mern_mongo mongosh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💡 3 things I'd tell myself before starting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Containers talk by service name, not localhost.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;http://mongo:27017&lt;/code&gt; not &lt;code&gt;http://localhost:27017&lt;/code&gt;. This will confuse you exactly once — now it won't confuse you at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Vite bakes env vars at build time.&lt;/strong&gt;&lt;br&gt;
Pass &lt;code&gt;VITE_*&lt;/code&gt; vars as Docker build args, not runtime env vars. Runtime env vars are for your Node server, not your compiled React bundle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Always add a MongoDB retry loop.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;depends_on&lt;/code&gt; is not a health check. MongoDB takes a few seconds to be ready — your Express server needs to handle that gracefully.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 What's next
&lt;/h2&gt;

&lt;p&gt;With this setup you're ready for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adding SSL&lt;/strong&gt; with Let's Encrypt + Nginx (next blog)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD pipeline&lt;/strong&gt; with GitHub Actions that builds and pushes your Docker image automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes&lt;/strong&gt; if you eventually need to scale beyond a single VPS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The foundation is solid. Everything else builds on top of this.&lt;/p&gt;




&lt;p&gt;If you made it this far — you're ahead of most MERN devs who are still debugging Node version mismatches on their VPS at 2am. 🙌&lt;/p&gt;

&lt;p&gt;Drop your questions in the comments — I check them all.&lt;/p&gt;

</description>
      <category>mern</category>
      <category>docker</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I Was Losing 2 Seconds on Every API Call in My MERN App — The Fix Was 5 Lines of Code published</title>
      <dc:creator>Maulik Solanki</dc:creator>
      <pubDate>Thu, 19 Mar 2026 05:09:16 +0000</pubDate>
      <link>https://dev.to/maulik_solanki_6660abf902/i-was-losing-2-seconds-on-every-api-call-in-my-mern-app-the-fix-was-5-lines-of-codepublished-29o1</link>
      <guid>https://dev.to/maulik_solanki_6660abf902/i-was-losing-2-seconds-on-every-api-call-in-my-mern-app-the-fix-was-5-lines-of-codepublished-29o1</guid>
      <description>&lt;p&gt;Most developers hit this wall and never know why their Express API feels &lt;strong&gt;slow&lt;/strong&gt; even after deployment.&lt;/p&gt;

&lt;p&gt;Not a server issue. Not a database issue.&lt;/p&gt;

&lt;p&gt;It was &lt;strong&gt;missing query indexing + no response caching&lt;/strong&gt; in MongoDB + Express.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔴 The Problem
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;/api/products&lt;/code&gt; call was doing a &lt;strong&gt;full collection scan&lt;/strong&gt; on 50,000+ documents — no index, no cache.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Average response time&lt;/td&gt;
&lt;td&gt;1800–2400ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documents scanned per call&lt;/td&gt;
&lt;td&gt;50,000+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Index used&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I only discovered this after opening the &lt;strong&gt;MongoDB Atlas Query Profiler&lt;/strong&gt; — something most devs never check until something breaks in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  🐌 Before — Slow Query (No Index)
&lt;/h2&gt;

&lt;p&gt;Here's what my Mongoose schema looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// mongoose model — no index defined&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;stock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&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;Product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;productSchema&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the Express route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Slow route — full collection scan every time&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;/products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="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;products&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;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({}).&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="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;products&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every single request was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scanning &lt;strong&gt;all 50,000+ documents&lt;/strong&gt; in the collection&lt;/li&gt;
&lt;li&gt;Sorting them in memory&lt;/li&gt;
&lt;li&gt;Returning the full Mongoose document objects (heavy!)&lt;/li&gt;
&lt;li&gt;Doing this &lt;strong&gt;again&lt;/strong&gt; on the very next request — no memory of the last call&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  ✅ After — Indexed + Cached (5 Lines Added)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Add a Compound Index to the Mongoose Schema
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;stock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Add compound index for frequent query pattern&lt;/span&gt;
&lt;span class="nx"&gt;productSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;productSchema&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells MongoDB to pre-sort data by &lt;code&gt;category&lt;/code&gt; (ascending) and &lt;code&gt;price&lt;/code&gt; (descending) — so queries matching this pattern &lt;strong&gt;skip the full scan entirely&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Add In-Memory Caching with &lt;code&gt;node-cache&lt;/code&gt;
&lt;/h3&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;node-cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;NodeCache&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;node-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Cache with 60-second TTL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodeCache&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;stdTTL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&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;/products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Check cache first&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cache&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;all_products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Cache miss — query DB with .lean() for speed&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;products&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;Product&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lean&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ✅ Returns plain JS objects, not Mongoose docs&lt;/span&gt;

    &lt;span class="c1"&gt;// Store in cache for next 60 seconds&lt;/span&gt;
    &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all_products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;products&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;products&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📉 The Result
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;First request&lt;/td&gt;
&lt;td&gt;~2100ms&lt;/td&gt;
&lt;td&gt;~180ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeated requests&lt;/td&gt;
&lt;td&gt;~2100ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~60ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB documents scanned&lt;/td&gt;
&lt;td&gt;50,000+&lt;/td&gt;
&lt;td&gt;Index only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory overhead&lt;/td&gt;
&lt;td&gt;High (Mongoose docs)&lt;/td&gt;
&lt;td&gt;Low (plain objects)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Response time dropped from &lt;strong&gt;~2100ms → 60ms&lt;/strong&gt; on repeated calls. MongoDB Atlas query profiler confirmed full index usage. Zero code refactor needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 3 Things I Now Do in Every MERN Project
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Add Compound Indexes for Frequent Query Patterns
&lt;/h3&gt;

&lt;p&gt;Think about how your data is queried most often. If you always filter by &lt;code&gt;category&lt;/code&gt; and sort by &lt;code&gt;price&lt;/code&gt;, that's your index:&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;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check if your index is being used in &lt;strong&gt;MongoDB Atlas → Performance Advisor&lt;/strong&gt; or by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In MongoDB shell or Compass&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
           &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
           &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;explain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;executionStats&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;Look for &lt;code&gt;"IXSCAN"&lt;/code&gt; in the &lt;code&gt;winningPlan&lt;/code&gt; — that means your index is being used. &lt;code&gt;"COLLSCAN"&lt;/code&gt; means full scan (bad ❌).&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Always Use &lt;code&gt;.lean()&lt;/code&gt; on Read-Only Queries
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Without .lean() — returns full Mongoose document&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;products&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;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ With .lean() — returns plain JS objects (~40% faster)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;products&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;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({}).&lt;/span&gt;&lt;span class="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;Mongoose documents come with a lot of overhead — getters, setters, validation methods, etc. If you're only &lt;strong&gt;reading&lt;/strong&gt; data and sending it as JSON, &lt;code&gt;.lean()&lt;/code&gt; strips all of that away.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Don't use &lt;code&gt;.lean()&lt;/code&gt; if you need Mongoose methods like &lt;code&gt;.save()&lt;/code&gt;, &lt;code&gt;.populate()&lt;/code&gt;, or virtuals on the result.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  3. Cache Data That Doesn't Change Every Second
&lt;/h3&gt;

&lt;p&gt;Not everything needs to be fresh from the database on every request. Product listings, category data, blog posts, config settings — these can safely be cached for 30–120 seconds.&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;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodeCache&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;stdTTL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 60 seconds default&lt;/span&gt;

&lt;span class="c1"&gt;// Generic cache wrapper utility&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCached&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;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchFn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&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;hit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cache&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hit&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;hit&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchFn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&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;/categories&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getCached&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all_categories&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="nx"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({}).&lt;/span&gt;&lt;span class="nf"&gt;lean&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="mi"&gt;120&lt;/span&gt; &lt;span class="c1"&gt;// cache for 2 minutes&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;categories&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;
  
  
  🛠️ Bonus: How to Profile Your MongoDB Queries
&lt;/h2&gt;

&lt;p&gt;If you're not sure where your slowdowns are, here's how to find them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1 — MongoDB Atlas Query Profiler&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your cluster → &lt;strong&gt;Performance Advisor&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Look for queries with high execution time and &lt;code&gt;COLLSCAN&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Atlas will even &lt;strong&gt;suggest indexes&lt;/strong&gt; for you&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Option 2 — Mongoose Debug Mode (local dev)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add this in your app.js / server.js&lt;/span&gt;
&lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;debug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This logs every query to the console — you can see exactly what's being executed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 3 — &lt;code&gt;.explain()&lt;/code&gt; on any query&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;explain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;executionStats&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;executionStats&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Look for: totalDocsExamined vs totalDocsReturned&lt;/span&gt;
&lt;span class="c1"&gt;// If they're very different → you need an index&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 Quick Summary
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ No index + No cache  →  2100ms (full scan every time)
✅ Index + .lean()      →  180ms  (first request)  
✅ Index + Cache        →  60ms   (repeated requests)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three small changes. Massive difference in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  🙋 What's Your Biggest MERN Bottleneck?
&lt;/h2&gt;

&lt;p&gt;Have you run into slow queries in your MERN app? Have a different caching strategy you prefer (Redis, etc.)? &lt;/p&gt;

&lt;p&gt;Drop it in the comments — I read every one. 👇&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If this helped you, consider following for more MERN performance tips, Node.js patterns, and full-stack deep dives every week.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>It’s Not Fun Anymore — How Digital Distraction Took Control of Us (and How to Take It Back)</title>
      <dc:creator>Maulik Solanki</dc:creator>
      <pubDate>Wed, 05 Nov 2025 04:43:52 +0000</pubDate>
      <link>https://dev.to/maulik_solanki_6660abf902/its-not-fun-anymore-how-digital-distraction-took-control-of-us-and-how-to-take-it-back-52kh</link>
      <guid>https://dev.to/maulik_solanki_6660abf902/its-not-fun-anymore-how-digital-distraction-took-control-of-us-and-how-to-take-it-back-52kh</guid>
      <description>&lt;p&gt;We used to go online to escape.&lt;br&gt;
Now, it feels like we can’t escape the &lt;em&gt;online&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You wake up → check your phone.&lt;br&gt;
You work → check notifications.&lt;br&gt;
You rest → scroll again.&lt;/p&gt;

&lt;p&gt;It’s not fun anymore.&lt;br&gt;
Your phone isn’t entertainment — it’s &lt;strong&gt;control&lt;/strong&gt;.&lt;br&gt;
And we’ve quietly built lives around constant distraction.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;⚙️ The Modern Trap No One Talks About&lt;/strong&gt;&lt;br&gt;
We’re not lazy.&lt;br&gt;
We’re &lt;em&gt;overstimulated&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Every scroll gives a tiny dopamine hit — and suddenly, real life feels “too slow.”&lt;br&gt;
We switch apps every 10 seconds and call it “rest.”&lt;br&gt;
We chase notifications but lose direction.&lt;br&gt;
We mistake being busy for being productive.&lt;/p&gt;

&lt;p&gt;Your brain isn’t broken — it’s overwhelmed.&lt;br&gt;
And the system is built to keep it that way.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;🧠 You Don’t Need Motivation — You Need Digital Discipline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Motivation fades.&lt;br&gt;
Focus gets stolen.&lt;br&gt;
But discipline? It’s the armor that protects your attention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Digital discipline&lt;/strong&gt; isn’t about deleting apps or disappearing offline.&lt;br&gt;
It’s about &lt;strong&gt;regaining control&lt;/strong&gt; — over your time, your thoughts, and your digital energy.&lt;/p&gt;

&lt;p&gt;Imagine staying focused for just 2 uninterrupted hours a day.&lt;br&gt;
No scrolling. No switching.&lt;br&gt;
You’d probably rebuild your entire life.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;🚀 Why I Wrote Digital Discipline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I got tired of watching people — including myself — lose hours every day to distraction.&lt;br&gt;
So I wrote a short, no-fluff eBook called &lt;a href="https://linktr.ee/Codermaan" rel="noopener noreferrer"&gt;Digital Discipline&lt;/a&gt;&lt;br&gt;
.&lt;/p&gt;

&lt;p&gt;It’s not about being “perfect.”&lt;br&gt;
It’s about being aware.&lt;br&gt;
It’s about breaking the invisible cycle that’s quietly stealing your focus, creativity, and peace.&lt;/p&gt;

&lt;p&gt;👉 Read it here:&lt;a href="https://linktr.ee/Codermaan" rel="noopener noreferrer"&gt; Digital Discipline – Regain Control of Your Focus&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;💬 Discussion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you think we’ve reached the point where focus has become a &lt;em&gt;luxury skill&lt;/em&gt;?&lt;br&gt;
Or are we still pretending we can multitask our way to peace?&lt;/p&gt;

&lt;p&gt;I’d love to hear your take.&lt;br&gt;
Because this isn’t just a productivity issue — it’s a _life _issue.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Discipline isn’t restriction. It’s direction.&lt;/strong&gt;&lt;br&gt;
Start small.&lt;br&gt;
Stay consistent.&lt;br&gt;
Reclaim your focus. ⚡&lt;/p&gt;

</description>
      <category>selfimprovement</category>
      <category>digitalminimalism</category>
      <category>productivity</category>
      <category>discipline</category>
    </item>
    <item>
      <title>You Don’t Need a Break From Screens — You Need Digital Discipline.</title>
      <dc:creator>Maulik Solanki</dc:creator>
      <pubDate>Tue, 04 Nov 2025 04:57:32 +0000</pubDate>
      <link>https://dev.to/maulik_solanki_6660abf902/you-dont-need-a-break-from-screens-you-need-digital-discipline-5a77</link>
      <guid>https://dev.to/maulik_solanki_6660abf902/you-dont-need-a-break-from-screens-you-need-digital-discipline-5a77</guid>
      <description>&lt;p&gt;I wasn’t burned out.&lt;br&gt;
I was &lt;strong&gt;digitally scattered&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My brain jumped between 5 tabs, 3 apps, and 100 thoughts — every 10 minutes.&lt;/p&gt;

&lt;p&gt;I called it “working.”&lt;br&gt;
But deep down, I knew I wasn’t _building _anything.&lt;/p&gt;

&lt;p&gt;Then I learned one concept that flipped everything:&lt;br&gt;
&lt;strong&gt;Digital Discipline&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s not a detox. It’s not about quitting tech.&lt;br&gt;
It’s about _mastering _it — so you control your focus, not your phone.&lt;/p&gt;

&lt;p&gt;⚡ After applying it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I stopped doom-scrolling without deleting a single app.&lt;/li&gt;
&lt;li&gt;My work felt peaceful again.&lt;/li&gt;
&lt;li&gt;I started finishing things — not just starting them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your mind feels overstimulated but underproductive… this book is your reset button.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://linktr.ee/Codermaan" rel="noopener noreferrer"&gt;Read “Digital Discipline” — your attention deserves a system.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>selfimprovement</category>
      <category>mindset</category>
      <category>discipline</category>
    </item>
    <item>
      <title>Can You Stay Focused for 2 Hours Without Checking Your Phone?</title>
      <dc:creator>Maulik Solanki</dc:creator>
      <pubDate>Sat, 01 Nov 2025 07:25:19 +0000</pubDate>
      <link>https://dev.to/maulik_solanki_6660abf902/can-you-stay-focused-for-2-hours-without-checking-your-phone-59pp</link>
      <guid>https://dev.to/maulik_solanki_6660abf902/can-you-stay-focused-for-2-hours-without-checking-your-phone-59pp</guid>
      <description>&lt;p&gt;Be honest.&lt;br&gt;
When was the last time you coded, designed, or wrote for 2 straight hours — no phone, no notifications, no distractions?&lt;/p&gt;

&lt;p&gt;Our digital world is built to break focus.&lt;br&gt;
But mastering your attention might be the real superpower of this decade.&lt;/p&gt;

&lt;p&gt;⌛ How do you protect your focus time?&lt;br&gt;
Share your tips 👇&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgflf1424yiahw34x6x6n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgflf1424yiahw34x6x6n.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(I talk about this deeply in my new eBook “Digital Discipline” — if you’re working on building stronger focus, you might like it.)&lt;br&gt;
👉 &lt;a href="https://linktr.ee/Codermaan" rel="noopener noreferrer"&gt;Read it here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>100daysofcode</category>
      <category>webdev</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>💭 Why You Need Digital Discipline (More Than Motivation)</title>
      <dc:creator>Maulik Solanki</dc:creator>
      <pubDate>Fri, 31 Oct 2025 07:16:25 +0000</pubDate>
      <link>https://dev.to/maulik_solanki_6660abf902/why-you-need-digital-discipline-more-than-motivation-2a5k</link>
      <guid>https://dev.to/maulik_solanki_6660abf902/why-you-need-digital-discipline-more-than-motivation-2a5k</guid>
      <description>&lt;p&gt;We live in a world full of notifications, distractions, and endless scrolling.&lt;br&gt;
Everyone talks about _motivation _— but let’s be real... motivation fades.&lt;br&gt;
What actually builds success?&lt;br&gt;
👉 &lt;strong&gt;Discipline&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Digital discipline means taking control of your time and attention — instead of letting your phone, social media, or apps control you.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔧 Quick ways to start:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Set intentional screen time limits&lt;/li&gt;
&lt;li&gt;Keep your phone away during focused work&lt;/li&gt;
&lt;li&gt;Unfollow noise — follow purpose&lt;/li&gt;
&lt;li&gt;Create before you consume&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple steps, massive results.&lt;br&gt;
Because the more disciplined your digital life is, the clearer your mind becomes.&lt;/p&gt;

&lt;p&gt;If you’ve been struggling to stay consistent or focused —&lt;br&gt;
I’ve written a short, actionable &lt;strong&gt;eBook on Digital Discipline&lt;/strong&gt; that helps you build lasting focus and habits in a noisy world.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fio1eed3tvabcsmptqo78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fio1eed3tvabcsmptqo78.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://linktr.ee/Codermaan" rel="noopener noreferrer"&gt;👉 Read or grab your copy here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start small. Stay consistent.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your focus is your real power. ⚡&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>discipline</category>
      <category>focus</category>
      <category>menifest</category>
      <category>avoidscreen</category>
    </item>
    <item>
      <title>💡 Why Every Developer Should Build Discipline Before Skills</title>
      <dc:creator>Maulik Solanki</dc:creator>
      <pubDate>Mon, 27 Oct 2025 12:08:02 +0000</pubDate>
      <link>https://dev.to/maulik_solanki_6660abf902/why-every-developer-should-build-discipline-before-skills-3m12</link>
      <guid>https://dev.to/maulik_solanki_6660abf902/why-every-developer-should-build-discipline-before-skills-3m12</guid>
      <description>&lt;p&gt;When people think about becoming great developers, they often rush straight to learning — &lt;strong&gt;JavaScript, React, APIs, frameworks,&lt;/strong&gt; the whole buffet.&lt;/p&gt;

&lt;p&gt;But here’s a truth most people ignore:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Without discipline, even the best skills fade away.&lt;br&gt;
You can have all the tutorials, the best laptop, the fastest internet, and still not grow — because discipline is the foundation everything else stands on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🌱 Skills Grow — But Discipline Keeps Them Alive
&lt;/h2&gt;

&lt;p&gt;Let’s be honest — learning to code isn’t always fun.&lt;br&gt;
There are days when nothing works, when you’re staring at an error for hours, or when a simple bug ruins your flow.&lt;/p&gt;

&lt;p&gt;That’s where &lt;strong&gt;discipline quietly steps in&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Discipline isn’t about forcing yourself to work 12 hours a day.&lt;br&gt;
It’s about showing up — especially when you don’t feel like it.&lt;/p&gt;

&lt;p&gt;It’s about pushing one more commit, writing one more line, reading one more doc page, and doing it consistently.&lt;/p&gt;

&lt;p&gt;Because consistency beats motivation every single time.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔁 The Cycle of the Average Developer
&lt;/h2&gt;

&lt;p&gt;Here’s what most beginners do (and we’ve all been there):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get super motivated by a YouTube video.&lt;/li&gt;
&lt;li&gt;Start learning a new framework.&lt;/li&gt;
&lt;li&gt;Lose motivation after a week.&lt;/li&gt;
&lt;li&gt;Repeat with another shiny new framework.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It’s not a skill problem — it’s a discipline problem.&lt;/p&gt;

&lt;p&gt;The best developers aren’t those who know everything — they’re the ones who stay long enough to finish what they start.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧭 How Discipline Transforms Your Coding Journey
&lt;/h2&gt;

&lt;p&gt;Think about the developers you look up to. They’re not superheroes.&lt;br&gt;
They just built systems that keep them moving even when their feelings don’t cooperate.&lt;/p&gt;

&lt;p&gt;Here’s what discipline does for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡ Builds momentum: You stop overthinking and start doing.&lt;/li&gt;
&lt;li&gt;🧩 Creates results: Small consistent work compounds faster than bursts of random effort.&lt;/li&gt;
&lt;li&gt;🎯 Brings clarity: You stop chasing every trend and focus on mastering one thing deeply.&lt;/li&gt;
&lt;li&gt;🤝 Earns respect: Clients, teammates, and employers all notice when you’re consistent and reliable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With discipline, you start creating your own opportunities — because people trust those who show up.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧘 Discipline Isn’t Restriction — It’s Freedom
&lt;/h2&gt;

&lt;p&gt;Most people think discipline kills creativity. The truth? It’s the opposite.&lt;/p&gt;

&lt;p&gt;When your mind isn’t constantly fighting distractions or laziness, you free up mental energy for creative ideas, clean architecture, better UI, or smarter problem-solving.&lt;/p&gt;

&lt;p&gt;Discipline doesn’t say “don’t rest.” It says, “Earn your rest.”&lt;/p&gt;

&lt;p&gt;And when you’ve earned it, rest feels 10x better.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ How to Build It (Even If You’re Struggling Now)
&lt;/h2&gt;

&lt;p&gt;Start small. Don’t aim to code for 6 hours a day. Just:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set one non-negotiable daily goal (e.g., code for 1 hour or write one meaningful commit).&lt;/li&gt;
&lt;li&gt;Create an environment that helps — remove distractions, silence notifications, use website blockers.&lt;/li&gt;
&lt;li&gt;Plan your next session before you finish the current one (so you know exactly where to start tomorrow).&lt;/li&gt;
&lt;li&gt;Keep a simple progress log — even a notebook or Notion page helps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every small act of discipline is a deposit into your future.&lt;/p&gt;

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

&lt;p&gt;In the end, discipline isn’t about coding — it’s about character.&lt;/p&gt;

&lt;p&gt;The same mindset that helps you debug an app will help you handle life, relationships, and growth. Because the real power isn’t in what you can do when you’re inspired — it’s in what you still do when you’re not.&lt;/p&gt;

&lt;p&gt;So before you chase your next skill, framework, or tutorial —&lt;br&gt;
build discipline first.&lt;/p&gt;

&lt;p&gt;Everything else will fall into place.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>discipline</category>
      <category>focus</category>
    </item>
  </channel>
</rss>
