<?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: AddWeb Solution Pvt Ltd</title>
    <description>The latest articles on DEV Community by AddWeb Solution Pvt Ltd (@addwebsolutionpvtltd).</description>
    <link>https://dev.to/addwebsolutionpvtltd</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%2Forganization%2Fprofile_image%2F11063%2F0b7a4ce4-43ab-4718-abd0-1d314bc88f99.png</url>
      <title>DEV Community: AddWeb Solution Pvt Ltd</title>
      <link>https://dev.to/addwebsolutionpvtltd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/addwebsolutionpvtltd"/>
    <language>en</language>
    <item>
      <title>Managing Environment Variables in React Properly</title>
      <dc:creator>Lakashya Upadhyay</dc:creator>
      <pubDate>Wed, 29 Apr 2026 07:36:27 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/managing-environment-variables-in-react-properly-2913</link>
      <guid>https://dev.to/addwebsolutionpvtltd/managing-environment-variables-in-react-properly-2913</guid>
      <description>&lt;p&gt;Environment variables in React often look simple at first, but they can quickly become a source of bugs, leaks, and deployment confusion if handled carelessly. In modern React apps, especially with Vite or CRA, the way you name, store, and access environment variables matters just as much as the values themselves.&lt;/p&gt;

&lt;p&gt;This guide walks through the most common mistakes developers make when managing environment variables in React, explains why they happen, and shows how to set up a clean and reliable environment configuration strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use the correct prefix for your build tool: REACT_APP_ for CRA and VITE_ for Vite.youtubevite&lt;/li&gt;
&lt;li&gt;Never store secrets in client-side environment variables, because anything shipped to the browser can be inspected.&lt;/li&gt;
&lt;li&gt;Keep .env.local for local-only values and add env files to .gitignore when appropriate.&lt;/li&gt;
&lt;li&gt;Use import.meta.env in Vite instead of process.env.&lt;/li&gt;
&lt;li&gt;Keep environment variables documented, consistent, and validated before the app uses them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Why This Matters&lt;/li&gt;
&lt;li&gt;Mistake 1: Using the Wrong Environment Variable Prefix&lt;/li&gt;
&lt;li&gt;Mistake 2: Treating Client-Side Env Vars Like Secrets&lt;/li&gt;
&lt;li&gt;Mistake 3: Mixing process.env and import.meta.env&lt;/li&gt;
&lt;li&gt;Mistake 4: Hardcoding URLs Instead of Using Config&lt;/li&gt;
&lt;li&gt;Mistake 5: Not Using .env.local Properly&lt;/li&gt;
&lt;li&gt;Mistake 6: Forgetting to Restart the Dev Server&lt;/li&gt;
&lt;li&gt;Mistake 7: Keeping Too Many Environment Files Without a Clear Rule&lt;/li&gt;
&lt;li&gt;Mistake 8: Not Validating Required Variables&lt;/li&gt;
&lt;li&gt;Mistake 9: Committing Sensitive .env Files to Git&lt;/li&gt;
&lt;li&gt;Mistake 10: Poor Naming and Documentation&lt;/li&gt;
&lt;li&gt;Frequently Asked Questions (FAQs)&lt;/li&gt;
&lt;li&gt;Interesting Facts &amp;amp; Stats&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Why This Matters
&lt;/h2&gt;

&lt;p&gt;React environment variables are usually used for API URLs, feature flags, analytics IDs, and deployment settings. The problem is that frontend apps are bundled for the browser, so misconfigured variables can lead to broken builds, undefined values, or exposed configuration that should never have been public.&lt;/p&gt;

&lt;p&gt;A small mistake like using API_URL instead of VITE_API_URL or REACT_APP_API_URL can make the value unavailable in your app. Another common issue is assuming environment variables are private when they are actually shipped to the client bundle.&lt;/p&gt;

&lt;p&gt;A good environment strategy makes your app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easier to deploy across dev, staging, and production.&lt;/li&gt;
&lt;li&gt;Safer to maintain in a team.&lt;/li&gt;
&lt;li&gt;Less likely to break from config mistakes.&lt;/li&gt;
&lt;li&gt;Easier to document and onboard new developers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Mistake 1: Using the Wrong Environment Variable Prefix
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Your variable name matters more than you think.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In React, the framework or build tool only exposes specific environment variables to the client. In Create React App, custom variables must begin with REACT_APP_, while Vite exposes variables prefixed with VITE_ through import.meta.env.youtube&lt;br&gt;
Example of the mistake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;text
API_URL=https://api.example.com
js
console.log(import.meta.env.API_URL);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How to fix it:&lt;br&gt;
Use the correct prefix for your tool.&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;text&lt;/span&gt;
&lt;span class="nx"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//api.example.com&lt;/span&gt;
&lt;span class="nx"&gt;js&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;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="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;CRA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="nx"&gt;text&lt;/span&gt;
&lt;span class="nx"&gt;REACT_APP_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//api.example.com&lt;/span&gt;
&lt;span class="nx"&gt;js&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;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;REACT_APP_API_URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Variables are actually available in the app.&lt;/li&gt;
&lt;li&gt;Builds behave consistently across environments.&lt;/li&gt;
&lt;li&gt;Your team knows which config values are intended for frontend use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Mistake 2: Treating Client-Side Env Vars Like Secrets
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Anything in a React bundle is public.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A very common misunderstanding is storing passwords, private tokens, or database credentials in frontend env files. React environment variables are bundled into client-side code, which means users can inspect them in the browser.&lt;/p&gt;

&lt;p&gt;Example of the mistake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;text
VITE_STRIPE_SECRET_KEY=sk_live_12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is dangerous because any secret exposed to the front end can be discovered by end users.&lt;/p&gt;

&lt;p&gt;How to fix it:&lt;br&gt;
Use frontend env vars only for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public API base URLs.&lt;/li&gt;
&lt;li&gt;Feature flags.&lt;/li&gt;
&lt;li&gt;Analytics public IDs.&lt;/li&gt;
&lt;li&gt;Non-sensitive deployment settings.
Keep sensitive secrets on the backend, and let your React app communicate with a server API instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better security.&lt;/li&gt;
&lt;li&gt;Less risk of accidental leaks.&lt;/li&gt;
&lt;li&gt;Cleaner separation between frontend and backend responsibilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  4. Mistake 3: Mixing process.env and import.meta.env
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Use the syntax your build tool expects.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of the most frequent bugs in Vite apps is using process.env, which is a CRA/Node-style pattern. Vite expects values from import.meta.env.&lt;/p&gt;

&lt;p&gt;Example of the mistake in Vite:&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;js&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;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;VITE_API_URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How to fix it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;js
console.log(import.meta.env.VITE_API_URL);
In CRA, the equivalent pattern is usually:
js
console.log(process.env.REACT_APP_API_URL);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoids undefined errors.&lt;/li&gt;
&lt;li&gt;Keep your code compatible with the correct build environment.&lt;/li&gt;
&lt;li&gt;Reduces confusion when switching between CRA and Vite.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Mistake 4: Hardcoding URLs Instead of Using Config
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Hardcoding works until deployment changes.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A lot of React apps start with hardcoded endpoints like &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;, then later break when deployed to staging or production. This makes the app harder to move between environments and increases refactoring work later.&lt;/p&gt;

&lt;p&gt;Example of the mistake:&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;js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8000/api&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;How to fix it:&lt;br&gt;
Move environment-specific values into env files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;text
VITE_API_URL=https://api.example.com
js
const baseUrl = import.meta.env.VITE_API_URL;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One codebase works across multiple environments.&lt;/li&gt;
&lt;li&gt;Easier switching between dev and production.&lt;/li&gt;
&lt;li&gt;Cleaner deployment pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Mistake 5: Not Using .env.local Properly
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Local overrides should stay local.”&lt;br&gt;
A common best practice is to place developer-specific values in .env.local, which is intended for local overrides and usually not committed. This is especially useful when each developer has different local endpoints, test credentials, or personal feature flags.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example structure:&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;text&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;development&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;production&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;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use .env for shared defaults.&lt;/li&gt;
&lt;li&gt;Use .env.local for machine-specific values.&lt;/li&gt;
&lt;li&gt;Use .env.development and .env.production for environment-specific behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cleaner collaboration.&lt;/li&gt;
&lt;li&gt;Fewer accidental git commits of personal values.&lt;/li&gt;
&lt;li&gt;Easier developer onboarding.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Mistake 6: Forgetting to Restart the Dev Server
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Env changes are not always hot-reloaded.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In many React setups, environment file changes do not always appear immediately in the running dev server. If a variable seems stuck or undefined, the first thing to try is restarting the server.&lt;/p&gt;

&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stop the dev server.&lt;/li&gt;
&lt;li&gt;Save the .env file.&lt;/li&gt;
&lt;li&gt;Start the server again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Saves debugging time.&lt;/li&gt;
&lt;li&gt;Prevents confusion when values appear stale.&lt;/li&gt;
&lt;li&gt;Ensures the bundler picks up the latest config.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Mistake 7: Keeping Too Many Environment Files Without a Clear Rule
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Too many env files can become configuration chaos.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s easy to end up with .env, .env.local, .env.development, .env.staging, .env.production, and several team-specific variants without a clear structure. That usually makes it hard to know which value is active in which environment.&lt;/p&gt;

&lt;p&gt;How to fix it:&lt;br&gt;
Define a simple convention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;.env for shared defaults.&lt;/li&gt;
&lt;li&gt;.env.local for developer-specific overrides.&lt;/li&gt;
&lt;li&gt;.env.development for local development.&lt;/li&gt;
&lt;li&gt;.env.production for production build values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easier to understand.&lt;/li&gt;
&lt;li&gt;Less confusion during deployment.&lt;/li&gt;
&lt;li&gt;More predictable configuration behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  9. Mistake 8: Not Validating Required Variables
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Missing config should fail early.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If your app depends on a value like VITE_API_URL, it should not silently continue with undefined. A missing environment variable often leads to broken API calls, blank screens, or confusing runtime errors.&lt;/p&gt;

&lt;p&gt;How to fix it:&lt;br&gt;
Check required values at app startup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;js
const apiUrl = import.meta.env.VITE_API_URL;

if (!apiUrl) {
  throw new Error('VITE_API_URL is missing');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fails fast during development.&lt;/li&gt;
&lt;li&gt;Prevents subtle runtime bugs.&lt;/li&gt;
&lt;li&gt;Makes deployment issues easier to catch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. Mistake 9: Committing Sensitive .env Files to Git
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Git remembers everything.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another common mistake is committing real environment files to source control. Even if the repo later becomes private, the secret may already have been exposed in history.&lt;/p&gt;

&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add .env, .env.local, and secret files to .gitignore.&lt;/li&gt;
&lt;li&gt;Commit only .env.example.&lt;/li&gt;
&lt;li&gt;Put placeholder values in examples.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;text&lt;/span&gt;
&lt;span class="nx"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nx"&gt;VITE_APP_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protects secrets.&lt;/li&gt;
&lt;li&gt;Makes setup easier for teammates.&lt;/li&gt;
&lt;li&gt;Keeps the repo safer and cleaner.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  11. Mistake 10: Poor Naming and Documentation
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Clear names save time later.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vague variable names like URL1, KEY, or TOKEN make maintenance harder. Good naming conventions help your team understand what belongs where and reduce mistakes when moving between projects.&lt;/p&gt;

&lt;p&gt;Better names:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;VITE_API_URL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VITE_APP_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VITE_GOOGLE_MAPS_KEY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;REACT_APP_BACKEND_URL&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use uppercase letters and underscores.&lt;/li&gt;
&lt;li&gt;Prefix only values meant for the frontend.&lt;/li&gt;
&lt;li&gt;Document each variable in your README or .env.example.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easier onboarding.&lt;/li&gt;
&lt;li&gt;Better readability.&lt;/li&gt;
&lt;li&gt;Less confusion during refactoring or deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12. Frequently Asked Questions (FAQs)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q. Can I use environment variables to hide secrets in React?&lt;/strong&gt;&lt;br&gt;
A. No. Anything shipped to the browser is visible to users, so secrets should stay on the backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q. Why is import.meta.env undefined in my Vite app?&lt;/strong&gt;&lt;br&gt;
A. The variable probably does not use the VITE_ prefix, or the dev server needs a restart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q. What prefix should I use in CRA?&lt;/strong&gt;&lt;br&gt;
A. Use REACT_APP_ for custom variables in Create React App.youtubeconfigu&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q. Should I commit .env files?&lt;/strong&gt;&lt;br&gt;
A. Usually not for real secrets. Commit .env.example instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q. Do I need separate env files for every environment?&lt;/strong&gt;&lt;br&gt;
A. Not always, but a clear convention for local, development, and production makes projects easier to manage.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. Interesting Facts &amp;amp; Stats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Vite exposes custom client-side env variables through import.meta.env, and only variables prefixed with VITE_ are exposed by default. Source: Vite Env Variables and Modes&lt;/li&gt;
&lt;li&gt;CRA requires the REACT_APP_ prefix for custom environment variables to be available in React code. Source: React .env File Hierarchy | Master Environment Variables in CRA &amp;amp; Vite&lt;/li&gt;
&lt;li&gt;Many environment variable bugs are not code bugs at all, but naming or build-tool configuration issues. Source: React Environment Variables: Basics, Tutorial, and Best Practices&lt;/li&gt;
&lt;li&gt;Using .env.local for local-only settings is a widely recommended pattern for safer collaboration. Source: React Environment Variables: Basics, Tutorial, and Best Practices&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Managing environment variables in React is less about storing values and more about building a predictable configuration system. Once you follow the right prefixing rules, keep secrets off the client, and separate local, development, and production values properly, environment setup becomes much more reliable.&lt;/p&gt;

&lt;p&gt;A good React environment strategy is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the correct build-tool syntax.&lt;/li&gt;
&lt;li&gt;Keep secrets on the server.&lt;/li&gt;
&lt;li&gt;Document variables clearly.&lt;/li&gt;
&lt;li&gt;Fail fast when config is missing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About the Author: Lakashya is a full‑stack Laravel developer at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWeb Solution &lt;/a&gt;specializing in scalable, real‑time applications with PHP and modern frontends.&lt;/p&gt;

</description>
      <category>reactbestpractices</category>
      <category>environmentvariables</category>
      <category>reactjsdevelopment</category>
      <category>frontendarchitecture</category>
    </item>
    <item>
      <title>Building Reusable UI Components in React (Clean &amp; Scalable Approach)</title>
      <dc:creator>Ankit Parmar</dc:creator>
      <pubDate>Mon, 27 Apr 2026 08:33:36 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/building-reusable-ui-components-in-react-clean-scalable-approach-gp1</link>
      <guid>https://dev.to/addwebsolutionpvtltd/building-reusable-ui-components-in-react-clean-scalable-approach-gp1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Programs must be written for people to read, and only incidentally for machines to execute.” - Harold Abelson&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Modern frontend applications grow fast-and without a solid component strategy, they become hard to maintain, inconsistent, and fragile. Reusable UI components solve this by promoting consistency, reducing duplication, and enabling scalable architecture.&lt;/p&gt;

&lt;p&gt;But simply “reusing components” isn’t enough. Poorly designed components can create more problems than they solve.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how to build clean, reusable, and scalable UI components in React, focusing on architecture, patterns, and real-world practices-not just syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Reusable Components Matter
&lt;/h2&gt;

&lt;p&gt;Without reusable components, teams often face:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI inconsistencies across pages&lt;/li&gt;
&lt;li&gt;Duplicate logic and styling&lt;/li&gt;
&lt;li&gt;Difficult debugging and updates&lt;/li&gt;
&lt;li&gt;Slower development velocity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reusable components help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standardize design and behavior&lt;/li&gt;
&lt;li&gt;Reduce code duplication&lt;/li&gt;
&lt;li&gt;Improve maintainability&lt;/li&gt;
&lt;li&gt;Speed up development&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Makes a Component Truly Reusable?
&lt;/h2&gt;

&lt;p&gt;A reusable component is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generic → Works in multiple contexts&lt;/li&gt;
&lt;li&gt;Composable → Can be combined with other components&lt;/li&gt;
&lt;li&gt;Configurable → Controlled via props&lt;/li&gt;
&lt;li&gt;Decoupled → Not tied to specific business logic
Bad example:
A UserDashboardCard hardcoded for one screen
Good example:
A Card component configurable via props&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Core Philosophy&lt;br&gt;
“Components should do one thing, and do it well.”&lt;br&gt;
Focus on:&lt;br&gt;
Separation of concerns&lt;br&gt;
Clear interfaces (props)&lt;br&gt;
Minimal assumptions&lt;/p&gt;
&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reusable components reduce duplication and improve maintainability&lt;/li&gt;
&lt;li&gt;Keep components small, focused, and composable&lt;/li&gt;
&lt;li&gt;Use props for flexibility, not hardcoded values&lt;/li&gt;
&lt;li&gt;Separate UI from business logic&lt;/li&gt;
&lt;li&gt;Follow consistent folder and naming conventions&lt;/li&gt;
&lt;li&gt;Avoid premature abstraction-refactor when patterns emerge&lt;/li&gt;
&lt;li&gt;Design systems and shared libraries scale teams effectively&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;What Are Reusable Components?&lt;/li&gt;
&lt;li&gt;Component Design Principles&lt;/li&gt;
&lt;li&gt;Types of Reusable Components&lt;/li&gt;
&lt;li&gt;Structuring Your Component Folder&lt;/li&gt;
&lt;li&gt;Props and Configuration&lt;/li&gt;
&lt;li&gt;Composition vs Inheritance&lt;/li&gt;
&lt;li&gt;Styling Strategies&lt;/li&gt;
&lt;li&gt;Handling State and Logic&lt;/li&gt;
&lt;li&gt;Building a Design System&lt;/li&gt;
&lt;li&gt;Common Mistakes to Avoid&lt;/li&gt;
&lt;li&gt;Why This Approach Works&lt;/li&gt;
&lt;li&gt;Watch Out For&lt;/li&gt;
&lt;li&gt;Next Steps You Can Take&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;As React applications grow, managing UI becomes increasingly complex. Without a reusable component strategy, developers often duplicate UI patterns, leading to inconsistent designs and bloated codebases.&lt;br&gt;
Reusable components solve this by encapsulating UI and behavior into modular building blocks. When done correctly, they create a system where features can be built faster and maintained more easily.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Simplicity is prerequisite for reliability.” - Edsger W. Dijkstra&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  2. What Are Reusable Components?
&lt;/h2&gt;

&lt;p&gt;Reusable components are UI elements that can be used across multiple parts of an application without modification.&lt;br&gt;
Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buttons&lt;/li&gt;
&lt;li&gt;Inputs&lt;/li&gt;
&lt;li&gt;Modals&lt;/li&gt;
&lt;li&gt;Cards&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tables&lt;br&gt;
They are not tied to:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Specific pages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Business logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hardcoded data&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3. Component Design Principles
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Single Responsibility&lt;/strong&gt;&lt;br&gt;
Each component should handle one concern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Reusability Over Specificity&lt;/strong&gt;&lt;br&gt;
Avoid embedding business logic inside UI components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Predictable API&lt;/strong&gt;&lt;br&gt;
Props should be clear, consistent, and minimal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Composition First&lt;/strong&gt;&lt;br&gt;
Build complex UI by combining smaller components.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Types of Reusable Components
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Presentational Components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus only on UI&lt;/li&gt;
&lt;li&gt;No business logic
Example:
Button, Card, Avatar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Container Components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle data and logic&lt;/li&gt;
&lt;li&gt;Pass data to presentational components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Layout Components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define page structure
Example:
Grid, Container, Sidebar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Compound Components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple components working together
Example:
Tabs, Dropdown, Accordion&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“Duplication is the root of all evil in software.” - Don’t Repeat Yourself principle&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  5. Structuring Your Component Folder
&lt;/h2&gt;

&lt;p&gt;A scalable 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;components/
  ui/
    Button/
      Button.jsx
      Button.css
      index.js
  forms/
    Input/
    Select/
  layout/
    Container/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Group by feature or type, not by file type&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Props and Configuration
&lt;/h2&gt;

&lt;p&gt;Props are the backbone of reusability.&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`btn btn-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"secondary"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Avoid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hardcoding values&lt;/li&gt;
&lt;li&gt;Passing too many unrelated props&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” - Martin Fowler&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  7. Composition vs Inheritance
&lt;/h2&gt;

&lt;p&gt;React favors composition over inheritance.&lt;br&gt;
Bad approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extending components like classes
Good approach:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Title&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Content&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This keeps components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flexible&lt;/li&gt;
&lt;li&gt;Readable&lt;/li&gt;
&lt;li&gt;Easy to extend&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  8. Styling Strategies
&lt;/h2&gt;

&lt;p&gt;Consistency in styling is critical.&lt;br&gt;
Options:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. CSS Modules&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scoped styles&lt;/li&gt;
&lt;li&gt;Prevent conflicts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Tailwind CSS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utility-first&lt;/li&gt;
&lt;li&gt;Fast development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Styled Components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamic styling&lt;/li&gt;
&lt;li&gt;Component-level styles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose one approach and stay consistent&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  9. Handling State and Logic
&lt;/h2&gt;

&lt;p&gt;Reusable components should avoid heavy logic.&lt;br&gt;
Good pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep logic outside&lt;/li&gt;
&lt;li&gt;Pass data via props
Bad:
&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;// tightly coupled&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserCard&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  10. Building a Design System
&lt;/h2&gt;

&lt;p&gt;At scale, reusable components evolve into a design system.&lt;br&gt;
A design system includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI components&lt;/li&gt;
&lt;li&gt;Design tokens (colors, spacing, typography)&lt;/li&gt;
&lt;li&gt;Usage guidelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistency across teams&lt;/li&gt;
&lt;li&gt;Faster onboarding&lt;/li&gt;
&lt;li&gt;Easier scaling
## 11. Common Mistakes to Avoid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Over-abstracting too early&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don’t generalize before patterns emerge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tight coupling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Avoid linking components to specific APIs or data sources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prop explosion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Too many props = hard to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignoring accessibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reusable components must support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keyboard navigation&lt;/li&gt;
&lt;li&gt;ARIA attributes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12. Why This Approach Works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reduces duplication&lt;/li&gt;
&lt;li&gt;Improves readability&lt;/li&gt;
&lt;li&gt;Encourages modular thinking&lt;/li&gt;
&lt;li&gt;Makes testing easier&lt;/li&gt;
&lt;li&gt;Scales across teams and projects&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“The best way to build complex systems is to assemble them from simple, well-defined parts.” - David Parnas&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Watch Out For&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Over-engineering simple components&lt;/li&gt;
&lt;li&gt;Creating unnecessary abstractions&lt;/li&gt;
&lt;li&gt;Mixing business logic with UI&lt;/li&gt;
&lt;li&gt;Inconsistent naming conventions&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Next Steps You Can Take&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Refactor duplicated UI into shared components&lt;/li&gt;
&lt;li&gt;Introduce a ui/ component library&lt;/li&gt;
&lt;li&gt;Document component usage&lt;/li&gt;
&lt;li&gt;Add Storybook for visual testing&lt;/li&gt;
&lt;li&gt;Enforce design consistency with linting&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Most large-scale React apps rely heavily on internal component libraries source&lt;/li&gt;
&lt;li&gt;Design systems can reduce development time significantly source&lt;/li&gt;
&lt;li&gt;Component-driven development is a standard in modern frontend engineering source&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  16. FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. How small should a component be?&lt;/strong&gt;&lt;br&gt;
Small enough to do one job, but not so small that it becomes meaningless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Should every component be reusable?&lt;/strong&gt;&lt;br&gt;
No. Only abstract when reuse is needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. How do I manage shared components?&lt;/strong&gt;&lt;br&gt;
Use a centralized components or ui directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Is Tailwind better for reusable components?&lt;/strong&gt;&lt;br&gt;
It depends-great for speed, but consistency depends on discipline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Can this scale for large apps?&lt;/strong&gt;&lt;br&gt;
Yes. This is exactly how large React apps are structured.&lt;/p&gt;

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

&lt;p&gt;Building reusable UI components in React is not just about avoiding duplication-it’s about creating a scalable, maintainable architecture.&lt;br&gt;
When done right, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cleaner code&lt;/li&gt;
&lt;li&gt;Faster development&lt;/li&gt;
&lt;li&gt;Consistent UI&lt;/li&gt;
&lt;li&gt;Easier scaling
If your goal is to build production-grade applications, investing in a strong component strategy isn’t optional-it’s foundational.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About the Author:&lt;em&gt;Ankit is a full-stack developer at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt; and AI enthusiast who crafts intelligent web solutions with PHP, Laravel, and modern frontend tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>frontend</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Handling API Errors &amp; Loading States in React (Clean UX Approach)</title>
      <dc:creator>Abodh Kumar</dc:creator>
      <pubDate>Wed, 22 Apr 2026 07:40:37 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/handling-api-errors-loading-states-in-react-clean-ux-approach-54o7</link>
      <guid>https://dev.to/addwebsolutionpvtltd/handling-api-errors-loading-states-in-react-clean-ux-approach-54o7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A user interface is like a joke. If you have to explain it, it is not that good. - Martin LeBlanc&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In any real-world React application, you will spend far more time handling what goes wrong than celebrating what goes right. Network failures, slow responses, timeouts, and server errors are not edge cases - they are everyday realities. How you communicate these states to your users defines the quality of your application's user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Always model three states - loading, error, and success - for every API call, no exceptions.&lt;/li&gt;
&lt;li&gt;Provide meaningful, context-specific error messages - never expose raw error objects to users.&lt;/li&gt;
&lt;li&gt;Use skeleton screens instead of spinners where possible to reduce perceived load time.&lt;/li&gt;
&lt;li&gt;Implement retry logic with exponential backoff for transient network failures.&lt;/li&gt;
&lt;li&gt;Centralize error handling with custom hooks to avoid repeating logic across components.&lt;/li&gt;
&lt;li&gt;Distinguish between network errors, HTTP errors, and validation errors - each requires different UX.&lt;/li&gt;
&lt;li&gt;Always cancel in-flight requests on component unmount to prevent memory leaks and ghost state updates&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Understanding the Three API States&lt;/li&gt;
&lt;li&gt;Handling Loading States - Spinners, Skeletons &amp;amp; Beyond&lt;/li&gt;
&lt;li&gt;Handling API Errors - Graceful Degradation&lt;/li&gt;
&lt;li&gt;Building a Custom useFetch Hook&lt;/li&gt;
&lt;li&gt;Advanced Techniques&lt;/li&gt;
&lt;li&gt;Stats &amp;amp; Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;Modern React applications are almost always data-driven, relying on REST APIs, GraphQL endpoints, or third-party services to power their interfaces. Whether you are building a dashboard that fetches analytics data, a shopping app that loads product listings, or a social platform that streams user posts, every API interaction introduces three inevitable possibilities: the data is loading, the data arrived successfully, or something went wrong.&lt;br&gt;
The difference between a great app and a frustrating one often comes down to how gracefully these states are handled. Users who encounter a blank screen during loading, a cryptic "undefined is not an object" message when an error occurs, or an interface that silently fails will lose trust in your product instantly.&lt;br&gt;
This article walks you through a complete, production-ready strategy for handling API errors and loading states in React - covering everything from basic useState patterns and skeleton screens to custom hooks, Axios interceptors, and React Query integration.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Understanding the Three API States
&lt;/h2&gt;

&lt;p&gt;Before writing a single line of code, it is essential to model your data fetching around three distinct states. Every API call in your application should reflect exactly one of these states at any given moment:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.1 The Loading State&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The loading state exists from the moment you initiate a request until a response (successful or otherwise) is received. Failing to model this state means users see stale data, empty screens, or worse - an interface that appears broken. A loading state should always trigger visible feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.2 The Success State&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the API returns the expected data with a successful status code (typically 2xx), the UI transitions to the success state. This is where you render the actual content. Even here, you must consider edge cases like empty arrays, null values, or partially missing fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.3 The Error State&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Any response outside the 2xx range, a network timeout, or a connection failure triggers the error state. This is the most neglected of the three, yet it is critical. Users need to know what failed and, where possible, what they can do about it.&lt;br&gt;
A foundational pattern using React's useState hook illustrates this model clearly:&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;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&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;span class="kd"&gt;const&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;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&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;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchUser&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="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="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;`/api/users/&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="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="s2"&gt;`Server error: &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;status&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="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="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="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AbortError&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;setError&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;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nf"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// cleanup on unmount&lt;/span&gt;
 &lt;span class="p"&gt;},&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ErrorMessage&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProfileCard&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Design is not just what it looks like and feels like. Design is how it works. - Steve Jobs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. Handling Loading States - Spinners, Skeletons &amp;amp; Beyond
&lt;/h2&gt;

&lt;p&gt;Not all loading indicators are equal. The choice of loading UI dramatically affects how users perceive your application's speed. Research in UX psychology consistently shows that users tolerate waiting much better when they receive structured, meaningful feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.1 Spinners - When to Use Them&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Spinners (circular progress indicators) are appropriate for short, unpredictable waits - typically actions like form submissions, delete confirmations, or quick one-off requests. They signal activity without implying structure about what is loading. Use them sparingly; overuse of spinners across an interface feels chaotic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Spinner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spinner-wrapper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spinner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sr-only&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.2 Skeleton Screens - The Gold Standard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Skeleton screens render placeholder shapes that mimic the final layout of your content before data arrives. They dramatically reduce perceived loading time by orienting the user to the page structure immediately. Facebook, LinkedIn, YouTube, and Slack all rely heavily on skeleton screens for their primary content feeds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductCardSkeleton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;card skeleton&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skeleton-image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skeleton-line wide&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skeleton-line medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skeleton-line narrow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;// CSS for pulsing animation&lt;/span&gt;
&lt;span class="cm"&gt;/*
.skeleton-line {
 height: 16px;
 background: linear-gradient(90deg, #e0e0e0 25%, #f0f0f0 50%, #e0e0e0 75%);
 background-size: 200% 100%;
 animation: shimmer 1.5s infinite;
 border-radius: 4px;
 margin-bottom: 10px;
}
@keyframes shimmer {
 0% { background-position: 200% 0; }
 100% { background-position: -200% 0; }
}
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.3 Progressive Loading&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For data-heavy pages, consider progressive loading: render critical above-the-fold content first, then fetch secondary sections lazily. This approach, combined with React's Suspense boundaries, delivers a fast initial paint even on slower connections.&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;Suspense&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lazy&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;react&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;HeavyChartSection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./HeavyChartSection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HeroMetrics&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Loads immediately */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ChartSkeleton&lt;/span&gt; &lt;span class="o"&gt;/&amp;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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HeavyChartSection&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Loads lazily */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Handling API Errors - Graceful Degradation
&lt;/h2&gt;

&lt;p&gt;Error handling is where most React applications fall short. A robust error handling strategy distinguishes between different failure modes and responds to each appropriately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.1 Classifying Errors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not all errors are the same. Build your error handling logic around these distinct categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network Errors - The request never reached the server (offline, DNS failure, CORS). The user needs to check their connection.&lt;/li&gt;
&lt;li&gt;HTTP 4xx Errors - Client-side errors (401 Unauthorized, 403 Forbidden, 404 Not Found, 422 Validation Failed). Each requires a specific response.&lt;/li&gt;
&lt;li&gt;HTTP 5xx Errors - Server-side errors (500 Internal Server Error, 503 Service Unavailable). The user should be reassured it is not their fault.&lt;/li&gt;
&lt;li&gt;Timeout Errors - The request took too long. Often appropriate to offer a retry.&lt;/li&gt;
&lt;li&gt;Validation Errors - The server rejected the data (422). Field-level feedback is critical here.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;classifyError&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;statusCode&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;statusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;network&lt;/span&gt;&lt;span class="dl"&gt;'&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 internet connection. Please check your network.&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;statusCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;'&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;Your session has expired. Please log in again.&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;statusCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;forbidden&lt;/span&gt;&lt;span class="dl"&gt;'&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;You do not have permission to view this resource.&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;statusCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notfound&lt;/span&gt;&lt;span class="dl"&gt;'&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;The requested resource could not be found.&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;statusCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;validation&lt;/span&gt;&lt;span class="dl"&gt;'&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;Please check your input and try again.&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;statusCode&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;'&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;Our servers are having trouble. Please try again shortly.&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;'&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;Something went wrong. Please try again.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.2 User-Friendly Error Components&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your error component should always communicate what went wrong, ideally offer a recovery action, and never expose raw error objects or stack traces to end users.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ErrorMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;type&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="nx"&gt;onRetry&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;icons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;📡&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🔐&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;forbidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🚫&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;notfound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🔍&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;⚠️&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;❓&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;
 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-icon&lt;/span&gt;&lt;span class="dl"&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;icons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Something&lt;/span&gt; &lt;span class="nx"&gt;went&lt;/span&gt; &lt;span class="nx"&gt;wrong&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-message&lt;/span&gt;&lt;span class="dl"&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;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onRetry&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onRetry&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;retry-button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nx"&gt;Try&lt;/span&gt; &lt;span class="nx"&gt;Again&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="p"&gt;)}&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.3 React Error Boundaries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For rendering errors (not async errors), React's Error Boundary class component catches exceptions thrown during render and prevents the entire tree from unmounting. Pair them with your async error states for comprehensive coverage.&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;class&lt;/span&gt; &lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hasError&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="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;getDerivedStateFromError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hasError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="nf"&gt;componentDidCatch&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;info&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;ErrorBoundary caught:&lt;/span&gt;&lt;span class="dl"&gt;'&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;info&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="c1"&gt;// Send to error tracking service (e.g., Sentry)&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="nf"&gt;render&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasError&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fallback&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DefaultErrorFallback&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&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;// Usage&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ErrorBoundary&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Something&lt;/span&gt; &lt;span class="nx"&gt;went&lt;/span&gt; &lt;span class="nx"&gt;wrong&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserDashboard&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ErrorBoundary&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Building a Custom useFetch Hook
&lt;/h2&gt;

&lt;p&gt;Repeating loading/error/success logic in every component is a maintenance nightmare. A custom hook centralizes this logic, ensures consistency, and makes components dramatically cleaner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.1 The useFetch Hook&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;function&lt;/span&gt; &lt;span class="nf"&gt;useFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;const&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;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;abortRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Abort any in-flight request&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;abortRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;abortRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&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;controller&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;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="nx"&gt;abortRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="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;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="nx"&gt;url&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;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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;errData&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;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="k"&gt;catch&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;throw&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errData&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&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="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;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;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="nf"&gt;setData&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="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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AbortError&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;setError&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="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;url&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

 &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;abortRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;abort&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;fetchData&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;refetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchData&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 in a component&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFetch&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/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;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProductListSkeleton&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ErrorMessage&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onRetry&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refetch&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&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;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EmptyState&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProductCard&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&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="nx"&gt;product&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.2 Adding Retry Logic with Exponential Backoff&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Transient network errors often resolve themselves within seconds. Implementing automatic retry with exponential backoff dramatically improves resilience in unstable network environments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchWithRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="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;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="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;status&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;// Retry on 5xx with exponential backoff: 1s, 2s, 4s&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;r&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;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&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="k"&gt;continue&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="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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="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;r&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;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&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="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;There are only two types of API calls: those that have failed, and those that have not failed yet. Plan for both. - Unknown, React Community Proverb&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  6. Advanced Techniques
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;6.1 Using React Query for Robust Data Fetching&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For production applications, React Query (now TanStack Query) provides battle-tested data fetching with built-in caching, background refetching, stale-while-revalidate patterns, and automatic retry - all without writing custom hooks from scratch.&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;useQuery&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;@tanstack/react-query&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&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;span class="kd"&gt;const&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;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isError&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;refetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&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="na"&gt;queryFn&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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;Failed to fetch user&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}),&lt;/span&gt;
   &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;retryDelay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;attemptIndex&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;attemptIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="na"&gt;staleTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&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="c1"&gt;// 5 minutes&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;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingSkeleton&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ErrorMessage&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onRetry&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refetch&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProfileCard&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.2 Axios Interceptors for Global Error Handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When using Axios, interceptors allow you to handle common error scenarios globally - such as redirecting to login on 401, showing a toast notification on 5xx errors, or refreshing tokens transparently.&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;axios&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;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;toast&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;react-hot-toast&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;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;baseURL&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nx"&gt;error&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;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="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;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&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;else&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;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;toast&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;Server error. Our team has been notified.&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;else&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;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;toast&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;Network error. Please check your connection.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.3 Optimistic Updates&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For actions like liking a post or toggling a bookmark, optimistic updates apply the change to the UI immediately before the server confirms it. If the request fails, the UI rolls back. This technique makes interfaces feel instantaneous.&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;instantaneous&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;LikeButton&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialLiked&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;liked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLiked&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialLiked&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;likeCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLikeCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleLike&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Optimistically update UI&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wasLiked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;liked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nf"&gt;setLiked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;wasLiked&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nf"&gt;setLikeCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;wasLiked&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;c&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;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/posts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/like`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;liked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;wasLiked&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="nf"&gt;setLiked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wasLiked&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="nf"&gt;setLikeCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;wasLiked&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;c&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;c&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;toast&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;Could not update like. Please try again.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleLike&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;liked&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;❤️&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🤍&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;likeCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.4 Global Loading Indicator&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For applications with many simultaneous API calls, a global loading bar (like the thin progress bar at the top of GitHub's pages) provides ambient feedback without disrupting the UI. Libraries like NProgress integrate cleanly with React.&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;NProgress&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;nprogress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&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;nprogress/nprogress.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// In your Axios instance&lt;/span&gt;
&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&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;config&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;NProgress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&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;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nx"&gt;response&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;NProgress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;done&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;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="nx"&gt;error&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;NProgress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;
  
  
  7. Stats &amp;amp; Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;According to Google research, 53% of mobile users abandon a site that takes longer than 3 seconds to load. Effective loading state UX directly impacts retention.Source: &lt;a href="https://www.thinkwithgoogle.com/marketing-strategies/app-and-mobile/mobile-page-speed-new-industry-benchmarks/" rel="noopener noreferrer"&gt;https://www.thinkwithgoogle.com/marketing-strategies/app-and-mobile/mobile-page-speed-new-industry-benchmarks/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A study by the Nielsen Norman Group found that users perceive skeleton screens as significantly faster than equivalent spinner-based loading experiences, even when actual load times are identical.
Source: &lt;a href="https://www.nngroup.com/articles/progress-indicators/" rel="noopener noreferrer"&gt;https://www.nngroup.com/articles/progress-indicators/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;According to State of JS surveys, React Query and SWR are now used by over 40% of React developers who fetch remote data, largely because of their built-in loading and error state management.
Source: &lt;a href="https://stateofjs.com" rel="noopener noreferrer"&gt;https://stateofjs.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Research from Amazon found that every 100ms increase in page load time reduced sales by 1%. Loading state UX is not just a UX concern - it is a business metric.Source: &lt;a href="https://www.fastcompany.com/1825005/how-one-second-could-cost-amazon-16-billion-sales" rel="noopener noreferrer"&gt;https://www.fastcompany.com/1825005/how-one-second-could-cost-amazon-16-billion-sales&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The HTTP Archive reports that the median mobile page makes over 70 separate HTTP requests. Without proper loading state management per request, the cumulative UX degradation is significant.
Source: &lt;a href="https://httparchive.org/reports/state-of-the-web" rel="noopener noreferrer"&gt;https://httparchive.org/reports/state-of-the-web&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sentry's 2023 developer survey found that unhandled promise rejections from API calls are among the top three sources of JavaScript errors in production React applications.
Source: &lt;a href="https://sentry.io/resources/developer-survey/" rel="noopener noreferrer"&gt;https://sentry.io/resources/developer-survey/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;According to UX research by Toptal, 88% of online consumers are less likely to return to a site after a bad user experience - silent API failures with no user feedback are a primary driver of this statistic. Source: &lt;a href="https://www.toptal.com/designers/ux/ux-statistics-insights-infographic" rel="noopener noreferrer"&gt;https://www.toptal.com/designers/ux/ux-statistics-insights-infographic&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Good error messages are a form of documentation. They tell the user what went wrong, why it matters, and what to do about it. - Jakob Nielsen, Nielsen Norman Group&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  8. FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Why should I model loading and error states separately rather than using a single "status" string?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ans: Using separate boolean flags (loading, error) is simpler for most cases and avoids state machine complexity. However, a single status enum ("idle" | "loading" | "success" | "error") is a valid and arguably more explicit pattern, especially as state logic grows. The critical principle is that all three states must always be represented - never leave any one implicit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What is the difference between a loading skeleton and a placeholder?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ans: A skeleton screen mimics the actual layout and shape of the content that will appear, giving users a structural preview. A generic placeholder (e.g., a grey box or spinner) gives no structural information. Skeleton screens outperform generic placeholders in perceived performance because they orient the user before the content arrives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Should I use React Query or write custom hooks for data fetching?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ans: For simple, one-off fetch calls, a custom hook is sufficient and avoids adding a dependency. For production apps with complex caching, pagination, background syncing, or optimistic updates, React Query (TanStack Query) or SWR are strongly recommended. They solve problems that custom hooks inevitably re-implement poorly over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. How should I handle validation errors returned from an API (HTTP 422)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ans: Parse the error response body to extract field-level validation messages and display them directly adjacent to the relevant form fields. Never show a generic error message for validation failures - users need to know exactly which field failed and why. React Hook Form and Formik both integrate well with server-side validation error patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. What should I do if a component unmounts before an API call completes?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ans: Always use an AbortController to cancel in-flight requests in your useEffect cleanup function. Without this, the component will attempt to update state after unmounting, causing the classic React warning about updating state on an unmounted component, and potentially causing memory leaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Is it ever appropriate to silently swallow API errors without user feedback?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ans: Only for non-critical background operations where failure has no impact on the user's task - for example, firing an analytics event or pre-fetching secondary content. For any operation the user explicitly triggered or depends on, always provide feedback. Silent failures destroy user trust.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. How should I handle errors in React Server Components (Next.js App Router)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ans: In Next.js App Router, use the error.tsx file convention to define error boundaries per route segment. For server-side data fetching, use try/catch in async server components and return appropriate fallback UI. The notFound() function handles 404 cases, while the error.tsx boundary handles unexpected errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. How do I test loading and error states in React components?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ans: Use Mock Service Worker (MSW) to intercept API calls in tests without mocking fetch directly. MSW allows you to simulate slow responses (for loading state tests), 4xx/5xx error responses (for error state tests), and successful responses - giving you realistic integration test coverage of all three states.&lt;/p&gt;

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

&lt;p&gt;Handling API errors and loading states cleanly is not a nice-to-have - it is the baseline of professional React development. Every layer described in this article serves a specific purpose in a complete, user-respecting data fetching strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicit state modeling ensures loading, error, and success are always accounted for - never left implicit.&lt;/li&gt;
&lt;li&gt;Skeleton screens reduce perceived loading time by orienting users to the page structure before content arrives.&lt;/li&gt;
&lt;li&gt;Error classification provides users with actionable, context-specific messages rather than generic failure notices.&lt;/li&gt;
&lt;li&gt;Custom hooks centralize data fetching logic and eliminate repetition across components.&lt;/li&gt;
&lt;li&gt;Retry logic and request cancellation add resilience and prevent memory leaks in production environments.&lt;/li&gt;
&lt;li&gt;React Query and Axios interceptors provide production-grade abstractions for complex data fetching scenarios.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;React provides all the primitives you need. The responsibility lies with developers to compose them thoughtfully, test all three states rigorously, and treat error handling as a first-class feature rather than an afterthought.&lt;/p&gt;

&lt;p&gt;The best UX is invisible - a user who never sees a cryptic error message, never stares at a blank screen, and always feels in control is experiencing excellent error handling. That invisibility is the mark of a truly polished React application.&lt;/p&gt;

&lt;p&gt;About the Author:&lt;em&gt;Abodh is a PHP and Laravel Developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWeb Solution&lt;/a&gt;, skilled in MySQL, REST APIs, JavaScript, Git, and Docker for building robust web applications.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Data Fetching Strategies in Next.js - SSR, SSG, ISR, and RSC</title>
      <dc:creator>Vatsal Acharya</dc:creator>
      <pubDate>Mon, 20 Apr 2026 10:46:48 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/data-fetching-strategies-in-nextjs-ssr-ssg-isr-and-rsc-5a2p</link>
      <guid>https://dev.to/addwebsolutionpvtltd/data-fetching-strategies-in-nextjs-ssr-ssg-isr-and-rsc-5a2p</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Performance is not a feature - it’s the foundation. Next.js gives you the tools to build it right.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next.js provides multiple data fetching strategies depending on performance and freshness needs.&lt;/li&gt;
&lt;li&gt;SSR fetches data on every request and is best for dynamic content.&lt;/li&gt;
&lt;li&gt;SSG generates pages at build time, making it extremely fast.&lt;/li&gt;
&lt;li&gt;ISR updates static pages after deployment without full rebuilds.&lt;/li&gt;
&lt;li&gt;RSC (React Server Components) is the modern default in App Router.&lt;/li&gt;
&lt;li&gt;Caching in Next.js is controlled using fetch options like cache and revalidate.&lt;/li&gt;
&lt;li&gt;Real-world apps use a combination of SSR, SSG, ISR, and RSC - not just one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Why data fetching strategy matters&lt;/li&gt;
&lt;li&gt;Quick comparison table&lt;/li&gt;
&lt;li&gt;Server-Side Rendering (SSR)&lt;/li&gt;
&lt;li&gt;Static Site Generation (SSG)

&lt;ul&gt;
&lt;li&gt;4b Incremental Static Regeneration (ISR)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;React Server Components (RSC)&lt;/li&gt;
&lt;li&gt;App Router vs Pages Router&lt;/li&gt;
&lt;li&gt;Caching in App Router&lt;/li&gt;
&lt;li&gt;Real-world app architecture&lt;/li&gt;
&lt;li&gt;Common mistakes &lt;/li&gt;
&lt;li&gt;Stats&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why does data fetching strategy actually matter?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a classic React app, data fetching is simple: useEffect fires after the component mounts, you hit an API, and update state.&lt;/p&gt;

&lt;p&gt;Easy to reason about - but there’s a problem:&lt;br&gt;
The user sees a blank or loading screen until JavaScript executes and the fetch completes.&lt;/p&gt;

&lt;p&gt;For small apps, this is fine.&lt;br&gt;
At scale, it becomes a serious UX and SEO issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next.js Solves This&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Modern web development is not about fetching data - it’s about fetching it intelligently.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next.js lets you decide:&lt;br&gt;
Where and when data should be fetched&lt;/p&gt;

&lt;p&gt;Each strategy is a tradeoff between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Freshness&lt;/li&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;li&gt;Server cost&lt;/li&gt;
&lt;li&gt;Complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Mental Model&lt;/strong&gt;&lt;br&gt;
Think of it as a spectrum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fully Dynamic → SSR&lt;/li&gt;
&lt;li&gt;Fully Static → SSG&lt;/li&gt;
&lt;li&gt;In Between → ISR + RSC&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Quick Reference - All Strategies at a Glance
&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%2Fmoxjm9hi1m7pebqrpsze.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%2Fmoxjm9hi1m7pebqrpsze.png" alt=" " width="656" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Note&lt;/strong&gt;&lt;br&gt;
RSC is not a replacement for SSR, SSG, or ISR.&lt;br&gt;
It’s a new rendering model that can behave like any of them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Strategy 01
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Server-Side Rendering (SSR)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a request comes in:&lt;br&gt;
Next.js fetches data on the server before sending HTML&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pages Router Example&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getServerSideProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;
 &lt;span class="nx"&gt;oop&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&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;getSession&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="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;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;permanent&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="p"&gt;}&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.example.com/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;session&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;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;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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Behavior&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs on every request&lt;/li&gt;
&lt;li&gt;Full HTML is returned&lt;/li&gt;
&lt;li&gt;No loading state on client&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to Use SSR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User-specific content&lt;/li&gt;
&lt;li&gt;Authentication logic&lt;/li&gt;
&lt;li&gt;Real-time data&lt;/li&gt;
&lt;li&gt;Accessing cookies/headers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to Use SSR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same data for all users&lt;/li&gt;
&lt;li&gt;Rarely changing content&lt;/li&gt;
&lt;li&gt;Performance-sensitive pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;br&gt;
SSR adds latency - your API speed = your page speed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Strategy 02
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Static Site Generation (SSG)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SSG generates pages at build time and serves static HTML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getStaticProps&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;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;https://api.example.com/posts&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;data&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;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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dynamic Routes Example&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getStaticPaths&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;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;https://api.example.com/posts&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;posts&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;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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;})),&lt;/span&gt;
   &lt;span class="na"&gt;fallback&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to Use SSG&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blogs&lt;/li&gt;
&lt;li&gt;Docs&lt;/li&gt;
&lt;li&gt;Landing pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tradeoff&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Very fast&lt;/li&gt;
&lt;li&gt;Not real-time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Strategy 03
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Incremental Static Regeneration (ISR)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ISR = SSG + automatic updates&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serve static page&lt;/li&gt;
&lt;li&gt;After interval → regenerate in background&lt;/li&gt;
&lt;li&gt;Next request gets fresh page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getStaticProps&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;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;https://api.example.com/products&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;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;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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&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="na"&gt;revalidate&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Revalidation only happens when a request comes&lt;br&gt;
 No traffic = no update&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On-Demand ISR (Better Approach)&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&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="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;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-webhook-secret&lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WEBHOOK_SECRET&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;Unauthorized&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;

 &lt;span class="k"&gt;await&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;revalidate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/products/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="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;revalidated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to Use ISR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product pages&lt;/li&gt;
&lt;li&gt;News&lt;/li&gt;
&lt;li&gt;CMS-driven content&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Strategy 04 (Modern Default)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;React Server Components (RSC)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“RSC changes the game: less JavaScript, better performance, cleaner architecture.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In App Router:&lt;br&gt;
 Components run on the server by default&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProducts&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;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;https://api.example.com/products&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="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;revalidate&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="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="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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&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;products&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;getProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="p"&gt;))}&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Controlling Behavior&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;fetch(url, { cache: 'force-cache' })   // SSG&lt;br&gt;
fetch(url, { cache: 'no-store' })      // SSR&lt;br&gt;
fetch(url, { next: { revalidate: 60 } }) // ISR&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Benefits&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No useEffect&lt;/li&gt;
&lt;li&gt;No client-side fetching&lt;/li&gt;
&lt;li&gt;Smaller JS bundle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important Rule&lt;/strong&gt;&lt;br&gt;
 Client components cannot import server components&lt;br&gt;
 Data flows server → client&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;App Router vs Pages Router&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pages Router&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;getServerSideProps / getStaticProps&lt;/li&gt;
&lt;li&gt;Page-level fetching&lt;/li&gt;
&lt;li&gt;Older system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;App Router&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Async components&lt;/li&gt;
&lt;li&gt;Component-level fetching&lt;/li&gt;
&lt;li&gt;Server-first approach&lt;/li&gt;
&lt;li&gt;Supports streaming
App Router is the future&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deep Dive
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Caching in App Router&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are 4 cache layers:&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%2F4b5uwwpy4xk9wao28s4a.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%2F4b5uwwpy4xk9wao28s4a.png" alt=" " width="340" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Issue&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;“Why is my data not updating?”&lt;br&gt;
 Usually due to Router cache&lt;/p&gt;

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

&lt;p&gt;router.refresh()&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revalidation Example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;import { revalidateTag } from 'next/cache'&lt;br&gt;
revalidateTag('products')&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Patterns
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Real-World Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;E-commerce&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Homepage → SSG&lt;/li&gt;
&lt;li&gt;Product Page → ISR&lt;/li&gt;
&lt;li&gt;Cart → SSR&lt;/li&gt;
&lt;li&gt;Layout → RSC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SaaS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Landing → SSG&lt;/li&gt;
&lt;li&gt;Dashboard → SSR&lt;/li&gt;
&lt;li&gt;Docs → ISR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real apps use combination of strategies&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The best data fetching strategy is not SSR or SSG - it’s choosing the right one at the right time.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Anti-Patterns
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Common Mistakes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Using SSR everywhere&lt;/strong&gt;&lt;br&gt;
Expensive + slow&lt;br&gt;
Use ISR instead&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Ignoring server/client boundary&lt;/strong&gt;&lt;br&gt;
Causes runtime errors&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. No error handling&lt;/strong&gt;&lt;br&gt;
Can crash entire page&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Fetching in client unnecessarily&lt;/strong&gt;&lt;br&gt;
Adds JS + loading delay&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Misunderstanding ISR timing&lt;/strong&gt;&lt;br&gt;
Low traffic = stale data&lt;/p&gt;

&lt;h2&gt;
  
  
  Stats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;According to Vercel, static generation can significantly improve performance by serving pre-rendered pages from a CDN, reducing server computation.Source: &lt;a href="https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation" rel="noopener noreferrer"&gt;https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Next.js has millions of weekly downloads and is one of the most widely used React frameworks.Source: &lt;a href="https://www.npmjs.com/package/next" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/next&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Next.js is used by companies like Netflix, TikTok, and Hulu for high-performance applications.Source: &lt;a href="https://nextjs.org/showcase" rel="noopener noreferrer"&gt;https://nextjs.org/showcase&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next.js was created and is maintained by Vercel.Source: &lt;a href="https://nextjs.org" rel="noopener noreferrer"&gt;https://nextjs.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Incremental Static Regeneration (ISR) was introduced in Next.js 9.5.Source: &lt;a href="https://nextjs.org/blog/next-9-5" rel="noopener noreferrer"&gt;https://nextjs.org/blog/next-9-5&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;React Server Components (RSC) became stable with the App Router in Next.js 13.Source: &lt;a href="https://nextjs.org/blog/next-13" rel="noopener noreferrer"&gt;https://nextjs.org/blog/next-13&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Next.js enables full-stack development by combining frontend and backend capabilities in a single framework.Source: &lt;a href="https://nextjs.org/docs" rel="noopener noreferrer"&gt;https://nextjs.org/docs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Is SSR outdated?&lt;/strong&gt;&lt;br&gt;
No - it’s still essential for dynamic and user-specific data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Is RSC replacing SSR/SSG?&lt;/strong&gt;&lt;br&gt;
No - it enhances them and gives more flexibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Can we mix all strategies?&lt;/strong&gt;&lt;br&gt;
Yes - and that’s the recommended approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Which is best for SEO?&lt;/strong&gt;&lt;br&gt;
SSG and SSR both are great for SEO.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Can ISR work with dynamic routes?&lt;/strong&gt;&lt;br&gt;
Yes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Where to store API keys?&lt;/strong&gt;&lt;br&gt;
Server-side only&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. App Router or Pages Router?&lt;/strong&gt;&lt;br&gt;
New projects → App Router&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. How to avoid waterfall fetches?&lt;/strong&gt;&lt;br&gt;
Use RSC&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Decision Tree&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ask:&lt;br&gt;
Does data change per user?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Yes → SSR / RSC (no-store)
Does data rarely change?&lt;/li&gt;
&lt;li&gt;Yes → SSG
Does it update periodically?&lt;/li&gt;
&lt;li&gt;Yes → ISR
Using App Router?&lt;/li&gt;
&lt;li&gt;Use RSC + fetch control&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Insight
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use Server Components for data&lt;/li&gt;
&lt;li&gt;Use Client Components for interactivity&lt;/li&gt;
&lt;li&gt;Use ISR for scalability&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Data fetching in Next.js is not about memorizing functions…&lt;br&gt;
It’s about choosing the right strategy at the right time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use SSR for dynamic data&lt;/li&gt;
&lt;li&gt;Use SSG for static content&lt;/li&gt;
&lt;li&gt;Use ISR for balance&lt;/li&gt;
&lt;li&gt;Use RSC for modern optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you understand this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your apps become faster&lt;/li&gt;
&lt;li&gt;Your architecture becomes scalable&lt;/li&gt;
&lt;li&gt;Your performance improves significantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About the Author:&lt;em&gt;Vatsal is a web developer at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;. Building web magic with Laravel, PHP, MySQL, Vue.js &amp;amp; more.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Docker Image with Multi-Stage Builds &amp; Docker Images Optimization</title>
      <dc:creator>Rajan Vavadia</dc:creator>
      <pubDate>Wed, 15 Apr 2026 08:24:49 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/docker-image-with-multi-stage-builds-docker-images-optimization-4379</link>
      <guid>https://dev.to/addwebsolutionpvtltd/docker-image-with-multi-stage-builds-docker-images-optimization-4379</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Docker is not a virtualization technology. It is an application delivery technology.” - Mike Coleman (Docker)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Overview: Multi-Stage Build Strategy (Builder + Production)&lt;/li&gt;
&lt;li&gt;Stage 1: Builder - Compile Extensions, Install Tools &amp;amp; Dependencies&lt;/li&gt;
&lt;li&gt;Stage 2: Production - Minimal Runtime Image&lt;/li&gt;
&lt;li&gt;The .dockerignore File&lt;/li&gt;
&lt;li&gt;Practical Setup (Step-by-step)&lt;/li&gt;
&lt;li&gt;Quotes&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Key Takeaways&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;This document explains how to build a production-ready PHP 8.4-FPM Docker image using a multi-stage Dockerfile. The image ships with all the PHP extensions, CLI tools (Composer, WP-CLI, Drush, Drupal Console), and Node.js needed for WordPress and Drupal projects - while keeping the final image lean and secure.&lt;/p&gt;

&lt;p&gt;The approach uses a two-stage build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stage 1 (Builder): Compiles PHP extensions, installs development tools, and downloads CLI utilities.&lt;/li&gt;
&lt;li&gt;Stage 2 (Production): Starts from a clean php:8.4-fpm base, copies only the compiled artifacts and runtime libraries, applies security hardening, and runs as a non-root user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why multi-stage?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A single-stage Dockerfile that compiles extensions and installs build tools leaves behind compilers, header files, and package caches that bloat the image and increase the attack surface. Multi-stage builds solve this by discarding everything that is not needed at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Overview: Multi-Stage Build Strategy (Builder + Production)
&lt;/h2&gt;

&lt;p&gt;Stage 1 (Builder) starts from php:8.4-fpm and installs: - 20+ PHP extensions using install-php-extensions (handles build dependencies and cleanup internally). - Composer, WP-CLI, Drush, and Drupal Console. - Node.js 20.x for front-end tooling.&lt;/p&gt;

&lt;p&gt;Stage 2 (Production) starts from a fresh php:8.4-fpm and: - Copies compiled extension .so files and their .ini configs from the builder. - Copies CLI binaries (Composer, WP-CLI, Drush, Drupal Console, Node.js). - Installs only the runtime shared libraries needed by the extensions. - Applies OPcache tuning and PHP security settings. - Creates a non-root user (appuser) for PHP-FPM. - Add a health check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why separate stages?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller image: Build tools (gcc, make, autoconf, header files) are discarded. Only runtime libraries remain.&lt;/li&gt;
&lt;li&gt;Faster pulls and deploys: Less data to transfer across registries and hosts.&lt;/li&gt;
&lt;li&gt;Reduced attack surface: No compilers or dev packages in production.&lt;/li&gt;
&lt;li&gt;Clearer troubleshooting: Build failures are isolated to Stage 1; runtime issues are isolated to Stage 2.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Stage 1: Builder - Compile Extensions, Install Tools &amp;amp; Dependencies
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;3.1 Base Image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FROM php:8.4-fpm AS builder&lt;br&gt;
We use the official php:8.4-fpm image (based on Debian 13 Trixie) as the builder base. This gives us the PHP source, phpize, and docker-php-ext-install out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.2 PHP Extension Installation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Single tool for all PHP extensions (handles build deps + cleanup internally)&lt;br&gt;
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/bin/&lt;/p&gt;

&lt;p&gt;Install all PHP extensions in one layer&lt;br&gt;
RUN install-php-extensions \&lt;br&gt;
        bcmath \&lt;br&gt;
        bz2 \&lt;br&gt;
        calendar \&lt;br&gt;
        exif \&lt;br&gt;
        gd \&lt;br&gt;
        gmp \&lt;br&gt;
        imagick \&lt;br&gt;
        intl \&lt;br&gt;
        mailparse \&lt;br&gt;
        mongodb \&lt;br&gt;
        mysqli \&lt;br&gt;
        opcache \&lt;br&gt;
        pcntl \&lt;br&gt;
        pdo \&lt;br&gt;
        pdo_mysql \&lt;br&gt;
        pdo_pgsql \&lt;br&gt;
        soap \&lt;br&gt;
        sockets \&lt;br&gt;
        sodium \&lt;br&gt;
        xsl \&lt;br&gt;
        zip&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why install-php-extensions?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It automatically installs the OS-level build dependencies (e.g., libpng-dev, libicu-dev), compiles the extension, and removes the build dependencies - all in one step.&lt;/li&gt;
&lt;li&gt;It replaces the manual apt-get install  &amp;amp;&amp;amp; docker-php-ext-configure &amp;amp;&amp;amp; docker-php-ext-install &amp;amp;&amp;amp; apt-get purge pattern.&lt;/li&gt;
&lt;li&gt;It supports PECL extensions (like imagick, mongodb, mailparse) with the same syntax.&lt;/li&gt;
&lt;li&gt;We use COPY --from=mlocati/php-extension-installer to pull the binary directly from the tool’s official image, without adding another FROM stage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Extensions included and why:&lt;/strong&gt;&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%2F4edabvvqwlqnwaur749j.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%2F4edabvvqwlqnwaur749j.png" alt=" " width="535" height="559"&gt;&lt;/a&gt;&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%2Fc2yz1pdflf39zxdatgwg.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%2Fc2yz1pdflf39zxdatgwg.png" alt=" " width="536" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.3 CLI Tools Installation&lt;/strong&gt;&lt;br&gt;
Install Composer, WP-CLI, Drush, and Drupal Console in one layer&lt;br&gt;
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \&lt;br&gt;
        git \&lt;br&gt;
        unzip \&lt;br&gt;
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/* \&lt;br&gt;
      Composer&lt;br&gt;
    &amp;amp;&amp;amp; curl -sSL &lt;a href="https://getcomposer.org/installer" rel="noopener noreferrer"&gt;https://getcomposer.org/installer&lt;/a&gt; | php -- --install-dir=/usr/local/bin --filename=composer \&lt;br&gt;
      WP-CLI&lt;br&gt;
    &amp;amp;&amp;amp; curl -sSL &lt;a href="https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar&lt;/a&gt; -o /usr/local/bin/wp \&lt;br&gt;
    &amp;amp;&amp;amp; chmod +x /usr/local/bin/wp \&lt;br&gt;
      Drupal Console&lt;br&gt;
    &amp;amp;&amp;amp; curl -sSL &lt;a href="https://drupalconsole.com/installer" rel="noopener noreferrer"&gt;https://drupalconsole.com/installer&lt;/a&gt; -o /usr/local/bin/drupal \&lt;br&gt;
    &amp;amp;&amp;amp; chmod +x /usr/local/bin/drupal&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Composer: PHP dependency manager. Installed globally at /usr/local/bin/composer.&lt;/li&gt;
&lt;li&gt;WP-CLI: WordPress command-line interface for managing WordPress installations.&lt;/li&gt;
&lt;li&gt;Drupal Console: CLI tool for generating boilerplate code and interacting with Drupal.&lt;/li&gt;
&lt;li&gt;git and unzip are needed by Composer to fetch packages; they are installed here but not carried over to the production stage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3.4 Drush Installation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ENV COMPOSER_HOME=/usr/local/share/composer&lt;br&gt;
RUN composer global require drush/drush:8.* --no-interaction --prefer-dist&lt;br&gt;
Drush (Drupal Shell) is installed globally via Composer. COMPOSER_HOME is set explicitly so the entire vendor directory can be copied to the production stage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.5 Node.js Installation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RUN curl -fsSL &lt;a href="https://deb.nodesource.com/setup_20.x" rel="noopener noreferrer"&gt;https://deb.nodesource.com/setup_20.x&lt;/a&gt; | bash - \&lt;br&gt;
    &amp;amp;&amp;amp; apt-get install -y --no-install-recommends nodejs \&lt;br&gt;
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;br&gt;
Node.js 20.x (LTS) is installed for front-end build tools (npm scripts, asset compilation). NVM is intentionally avoided - a single global Node.js installation is simpler and more predictable in a container.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Build once, run anywhere - but make sure what you build is only what you need.” - Container best practice principle&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Stage 2: Production - Minimal Runtime Image
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;4.1 Fresh Base and Labels&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FROM php:8.4-fpm AS production&lt;/p&gt;

&lt;p&gt;LABEL maintainer="AddWeb Solutions" \&lt;br&gt;
      description="PHP 8.4-FPM production image with WordPress/Drupal tooling"&lt;br&gt;
A fresh php:8.4-fpm base - none of the builder’s build tools, caches, or temp files exist here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.2 Copying Artifacts from Builder&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Copy PHP extensions and their configs from builder&lt;br&gt;
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/&lt;br&gt;
COPY --from=builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/&lt;/p&gt;

&lt;p&gt;Copy CLI tools from builder&lt;br&gt;
COPY --from=builder /usr/local/bin/composer /usr/local/bin/composer&lt;br&gt;
COPY --from=builder /usr/local/bin/wp /usr/local/bin/wp&lt;br&gt;
COPY --from=builder /usr/local/bin/drupal /usr/local/bin/drupal&lt;br&gt;
COPY --from=builder /usr/local/share/composer /usr/local/share/composer&lt;/p&gt;

&lt;p&gt;Copy Node.js from builder&lt;br&gt;
COPY --from=builder /usr/bin/node /usr/bin/node&lt;br&gt;
COPY --from=builder /usr/bin/npm /usr/bin/npm&lt;br&gt;
COPY --from=builder /usr/bin/npx /usr/bin/npx&lt;br&gt;
COPY --from=builder /usr/lib/node_modules /usr/lib/node_modules&lt;br&gt;
COPY --from=builder selectively pulls only the compiled .so files, .ini configs, and CLI binaries. Everything else (compilers, header files, build caches) is left behind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.3 Runtime Libraries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \&lt;br&gt;
        # Runtime libs required by PHP extensions&lt;br&gt;
        libbz2-1.0 \&lt;br&gt;
        libfreetype6 \&lt;br&gt;
        libgmp10 \&lt;br&gt;
        libicu76 \&lt;br&gt;
        libjpeg62-turbo \&lt;br&gt;
        libmagickwand-7.q16-10 \&lt;br&gt;
        libavif16 \&lt;br&gt;
        libpng16-16 \&lt;br&gt;
        libpq5 \&lt;br&gt;
        libxslt1.1 \&lt;br&gt;
        libzip5 \&lt;br&gt;
        # Essential runtime utilities only&lt;br&gt;
        cron \&lt;br&gt;
        curl \&lt;br&gt;
        default-mysql-client \&lt;br&gt;
        ffmpeg \&lt;br&gt;
        sendmail \&lt;br&gt;
        supervisor \&lt;br&gt;
        unzip \&lt;br&gt;
        sqlite3 \&lt;br&gt;
    &amp;amp;&amp;amp; apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \&lt;br&gt;
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key points:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runtime libs only: We install the shared libraries (.so files) that the compiled PHP extensions link against. These are the -dev-less counterparts (e.g., libpng16-16 not libpng-dev).&lt;/li&gt;
&lt;li&gt;Debian Trixie package names: Since php:8.4-fpm is based on Debian 13 (Trixie), some package names differ from Bookworm (e.g., libicu76 instead of libicu72, libmagickwand-7.q16-10 instead of libmagickwand-6.q16-6, libzip5 instead of libzip4).&lt;/li&gt;
&lt;li&gt;Essential utilities: cron (scheduled tasks), curl (health checks, API calls), default-mysql-client (database operations), ffmpeg (media processing), sendmail (email delivery), supervisor (process management), unzip, sqlite3.&lt;/li&gt;
&lt;li&gt;Cleanup: apt-get purge --auto-remove removes packages that were pulled in only as install dependencies, and rm -rf /var/lib/apt/lists/* clears the package cache.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Runtime libraries mapped to extensions:&lt;/strong&gt;&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%2Fu3brfn5xfihef1y335bq.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%2Fu3brfn5xfihef1y335bq.png" alt=" " width="536" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.4 Drush Symlink&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ENV COMPOSER_HOME=/usr/local/share/composer&lt;br&gt;
RUN ln -s /usr/local/share/composer/vendor/bin/drush /usr/local/bin/drush&lt;br&gt;
Makes drush available in $PATH without modifying the PATH variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.5 OPcache Tuning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RUN { \&lt;br&gt;
        echo 'opcache.memory_consumption=128'; \&lt;br&gt;
        echo 'opcache.interned_strings_buffer=8'; \&lt;br&gt;
        echo 'opcache.max_accelerated_files=4000'; \&lt;br&gt;
        echo 'opcache.revalidate_freq=60'; \&lt;br&gt;
        echo 'opcache.fast_shutdown=1'; \&lt;br&gt;
        echo 'opcache.enable_cli=1'; \&lt;br&gt;
        echo 'opcache.validate_timestamps=0'; \&lt;br&gt;
    } &amp;gt; /usr/local/etc/php/conf.d/opcache-recommended.ini&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%2Fe9nvrbpu99xvyxqercl6.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%2Fe9nvrbpu99xvyxqercl6.png" alt=" " width="536" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;validate_timestamps=0 is a production optimization - PHP never starts the filesystem to check if files have changed. When you deploy new code, restart PHP-FPM to pick up the changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.6 Security Hardening&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RUN { \&lt;br&gt;
        echo 'expose_php=Off'; \&lt;br&gt;
        echo 'display_errors=Off'; \&lt;br&gt;
        echo 'log_errors=On'; \&lt;br&gt;
        echo 'error_log=/dev/stderr'; \&lt;br&gt;
        echo 'allow_url_fopen=Off'; \&lt;br&gt;
    } &amp;gt; /usr/local/etc/php/conf.d/security.ini&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%2Ft5jjgi920b7j3onuttrf.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%2Ft5jjgi920b7j3onuttrf.png" alt=" " width="535" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.7 Non-Root User&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RUN groupadd -g 1000 appuser &amp;amp;&amp;amp; useradd -u 1000 -g appuser -m appuser&lt;/p&gt;

&lt;p&gt;WORKDIR /var/www/html&lt;br&gt;
RUN chown -R appuser:appuser /var/www/html&lt;br&gt;
Running PHP-FPM as a non-root user reduces the blast radius if the application is compromised. The appuser (UID 1000) owns the web root.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.8 Health Check&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HEALTHCHECK --interval=30s --timeout=5s --retries=3 \&lt;br&gt;
    CMD php-fpm-healthcheck || kill -0 $(cat /var/run/php-fpm.pid 2&amp;gt;/dev/null) || exit 1&lt;br&gt;
Docker checks every 30 seconds whether PHP-FPM is responding. After 3 consecutive failures, the container is marked unhealthy, and orchestrators (Docker Compose, Swarm, Kubernetes) can restart it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.9  Expose and CMD&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;EXPOSE 9000&lt;/p&gt;

&lt;p&gt;CMD ["php-fpm"]&lt;br&gt;
PHP-FPM listens on port 9000 (FastCGI). A reverse proxy (Nginx, Apache, Caddy) forwards requests to this port.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The .dockerignore File
&lt;/h2&gt;

&lt;p&gt;.git&lt;br&gt;
.github&lt;br&gt;
.gitignore&lt;br&gt;
&lt;em&gt;.md&lt;br&gt;
LICENSE&lt;br&gt;
docker-compose&lt;/em&gt;.yml&lt;br&gt;
.env*&lt;br&gt;
.vscode&lt;br&gt;
.idea&lt;br&gt;
node_modules&lt;br&gt;
vendor&lt;br&gt;
.docker&lt;/p&gt;

&lt;p&gt;The .dockerignore prevents unnecessary files from being sent to the Docker build context. This speeds up builds and avoids leaking secrets (.env files) or bloating the image with node_modules or vendor directories.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Practical Setup (Step-by-step)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;6.1 Build the Image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;docker build -t php8.4-multistage --target production .&lt;br&gt;
The --target production flag tells Docker to stop at the production stage and discard the builder. If --target is omitted, Docker builds up to the last stage (which is already in production in this Dockerfile).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.2 Run the Container&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;docker run -d \&lt;br&gt;
    --name php-app \&lt;br&gt;
    -p 9000:9000 \&lt;br&gt;
    -v ./src:/var/www/html \&lt;br&gt;
    php8.4-multistage&lt;br&gt;
Mount your application source code at /var/www/html. PHP-FPM will serve it on port 9000.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.3 Pair with Nginx (docker-compose example)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;version: '3.8'&lt;/p&gt;

&lt;p&gt;services:&lt;br&gt;
  php:&lt;br&gt;
    build:&lt;br&gt;
      context: .&lt;br&gt;
      target: production&lt;br&gt;
    volumes:&lt;br&gt;
      - ./src:/var/www/html&lt;br&gt;
    networks:&lt;br&gt;
      - app-network&lt;/p&gt;

&lt;p&gt;nginx:&lt;br&gt;
    image: nginx:alpine&lt;br&gt;
    ports:&lt;br&gt;
      - "80:80"&lt;br&gt;
    volumes:&lt;br&gt;
      - ./src:/var/www/html&lt;br&gt;
      - ./nginx.conf:/etc/nginx/conf.d/default.conf&lt;br&gt;
    depends_on:&lt;br&gt;
      - php&lt;br&gt;
    networks:&lt;br&gt;
      - app-network&lt;/p&gt;

&lt;p&gt;networks:&lt;br&gt;
  app-network:&lt;br&gt;
    driver: bridge&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.4 Verify Extensions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;docker exec php-app php -m&lt;br&gt;
This lists all loaded PHP modules. Confirm that gd, imagick, intl, opcache, pdo_mysql, etc., are all present.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.5 Verify CLI Tools&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;docker exec php-app composer --version&lt;br&gt;
docker exec php-app wp --version&lt;br&gt;
docker exec php-app drush --version&lt;br&gt;
docker exec php-app node --version&lt;br&gt;
docker exec php-app npm --version&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.6 Check phpinfo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a phpinfo file&lt;br&gt;
docker exec php-app bash -c "echo '&amp;lt;?php phpinfo();' &amp;gt; /var/www/html/info.php"&lt;/p&gt;

&lt;p&gt;Quick test with built-in server&lt;br&gt;
docker exec -d php-app php -S 0.0.0.0:8085 -t /var/www/html&lt;br&gt;
Open &lt;a href="http://localhost:8085/info.php" rel="noopener noreferrer"&gt;http://localhost:8085/info.php&lt;/a&gt; in your browser to see the full PHP configuration. Remove info.php after testing - never leave it exposed in production.&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%2Frse2r80h0lmn7qh3bmcj.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%2Frse2r80h0lmn7qh3bmcj.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.7 Common Improvements (optional)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use BuildKit cache mounts to speed up repeated builds: RUN --mount=type=cache,target=/var/cache/apt apt-get update &amp;amp;&amp;amp; ...&lt;/li&gt;
&lt;li&gt;Pin the PHP version (e.g., php:8.4.18-fpm) for reproducible builds instead of using the floating 8.4-fpm tag.&lt;/li&gt;
&lt;li&gt;Add a .env-based PHP config layer for settings that vary between environments (memory_limit, upload_max_filesize).&lt;/li&gt;
&lt;li&gt;Use Docker Compose profiles to add Xdebug only in development (avoid Xdebug in production).&lt;/li&gt;
&lt;li&gt;Scan the image with Trivy or Docker Scout for vulnerability reporting before pushing to a registry.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“The art of simplicity is a puzzle of complexity.” - Douglas Horton&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  8. FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1. Why use multi-stage builds instead of a single Dockerfile?&lt;/strong&gt; &lt;br&gt;
A. A single-stage build carries compilers, dev headers, and package caches into the final image. Multi-stage builds discard all of that, resulting in a smaller, more secure image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2. Why install-php-extensions instead of docker-php-ext-install?&lt;/strong&gt; A. install-php-extensions handles OS dependency installation, extension compilation, and cleanup automatically. It also supports PECL extensions (imagick, mongodb, mailparse) with the same syntax, eliminating the need for separate pecl install commands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3. Why is the base image Debian Trixie? Can I use Bookworm or Alpine?&lt;/strong&gt; &lt;br&gt;
A. The official php:8.4-fpm tag is built on Debian 13 (Trixie) as of 2025. If you need Bookworm, use php:8.4-fpm-bookworm. Alpine (php:8.4-fpm-alpine) is smaller but uses musl libc, which can cause compatibility issues with some extensions (notably ImageMagick).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4. Why are the runtime library package names different from older guides?&lt;/strong&gt; &lt;br&gt;
A. Debian Trixie renamed several packages as part of the 64-bit time_t transition and library version bumps. For example: libicu72 became libicu76, libmagickwand-6.q16-6 became libmagickwand-7.q16-10, and libzip4 became libzip5. Always verify package names against the base image’s Debian version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5. How do I find the correct runtime library names if I change the base image?&lt;/strong&gt; &lt;br&gt;
A. Run a temporary container and use ldd to check for missing libraries:&lt;br&gt;
docker run --rm your-image bash -c \&lt;br&gt;
  "for so in /usr/local/lib/php/extensions/&lt;em&gt;/&lt;/em&gt;.so; do \&lt;br&gt;
     ldd \$so 2&amp;gt;/dev/null | grep 'not found'; \&lt;br&gt;
   done"&lt;br&gt;
Then search for the correct package with apt-cache search .&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q6. What does validate_timestamps=0 mean for deployments?&lt;/strong&gt; &lt;br&gt;
A. OPcache will never check if PHP files on disk have changed. This avoids filesystem stat calls on every request (faster). The tradeoff: after deploying new code, you must restart PHP-FPM (docker restart ) to pick up changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q7. Why create a non-root user?&lt;/strong&gt; &lt;br&gt;
A. Running as root inside a container means a compromised application has full control over the container filesystem. A non-root user limits the damage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q8. Can I add Xdebug for local development?&lt;/strong&gt; &lt;br&gt;
A. Yes, but do not include it in the production image. Use a separate development stage or a Docker Compose override file that installs Xdebug on top of the production image.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Multi-stage builds separate build-time complexity from runtime simplicity.&lt;/li&gt;
&lt;li&gt;install-php-extensions eliminates the manual dance of installing dev packages, compiling, and cleaning up.&lt;/li&gt;
&lt;li&gt;Always match runtime library package names to the base image’s Debian version (Trixie uses libicu76, libzip5, libmagickwand-7.q16-10, libavif16).&lt;/li&gt;
&lt;li&gt;OPcache with validate_timestamps=0 is a significant performance win for production.&lt;/li&gt;
&lt;li&gt;Security hardening (expose_php=Off, display_errors=Off, allow_url_fopen=Off) should be the default, not an afterthought.&lt;/li&gt;
&lt;li&gt;Non-root user + health check + .dockerignore round out a production-ready setup.&lt;/li&gt;
&lt;li&gt;Use ldd to diagnose missing shared libraries when extensions fail to load.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This multi-stage Dockerfile provides a clean, repeatable way to build a PHP 8.4-FPM production image with everything needed for WordPress and Drupal projects. The builder stage handles all the heavy lifting - compiling extensions, installing Composer, WP-CLI, Drush, Drupal Console, and Node.js - while the production stage starts fresh and copies only what is needed at runtime. Combined with OPcache tuning, security hardening, a non-root user, and a health check, the result is an image that is smaller, faster, and more secure than a traditional single-stage build. When paired with Nginx via Docker Compose, it forms a solid foundation for deploying PHP applications in any environment.&lt;/p&gt;

&lt;p&gt;About the Author:&lt;em&gt;Rajan is a DevOps Engineer at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;, specializing in automation infrastructure, Optimize the CI/CD Pipelines and ensuring seamless deployments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>dockerfile</category>
      <category>dockerignore</category>
      <category>multistagebuilds</category>
    </item>
    <item>
      <title>Architecting Large-Scale Next.js Applications (Folder Structure, Patterns, Best Practices)</title>
      <dc:creator>Mayank Goyal</dc:creator>
      <pubDate>Mon, 13 Apr 2026 10:25:46 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/architecting-large-scale-nextjs-applications-folder-structure-patterns-best-practices-2dpj</link>
      <guid>https://dev.to/addwebsolutionpvtltd/architecting-large-scale-nextjs-applications-folder-structure-patterns-best-practices-2dpj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Good architecture makes the system easy to understand; great architecture makes it hard to break.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Feature-based architecture is critical&lt;/li&gt;
&lt;li&gt;Separate UI, logic, and data layers&lt;/li&gt;
&lt;li&gt;Prefer server components for performance&lt;/li&gt;
&lt;li&gt;Centralize API logic&lt;/li&gt;
&lt;li&gt;Use scalable state management&lt;/li&gt;
&lt;li&gt;Optimize early, not later&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Why Architecture Matters&lt;/li&gt;
&lt;li&gt;Core Principles of Scalable Architecture&lt;/li&gt;
&lt;li&gt;Advanced Folder Structure (Enterprise-Level)&lt;/li&gt;
&lt;li&gt;Architectural Patterns (Deep Dive)&lt;/li&gt;
&lt;li&gt;State Management at Scale&lt;/li&gt;
&lt;li&gt;Data Fetching &amp;amp; API Layer Design&lt;/li&gt;
&lt;li&gt;Authentication &amp;amp; Authorization Architecture&lt;/li&gt;
&lt;li&gt;Performance Optimization (Advanced)&lt;/li&gt;
&lt;li&gt;Error Handling &amp;amp; Logging&lt;/li&gt;
&lt;li&gt;Testing Strategy (Production-Ready)&lt;/li&gt;
&lt;li&gt;Dev Experience &amp;amp; Code Quality&lt;/li&gt;
&lt;li&gt;Deployment &amp;amp; Infrastructure Strategy&lt;/li&gt;
&lt;li&gt;Real-World Example (Enterprise Dashboard)&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;Stats&lt;/li&gt;
&lt;li&gt;FAQ’s&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Building small Next.js apps is easy. Scaling them to support millions of users, multiple developers, and complex business logic is not.&lt;br&gt;
Large-scale applications require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean architecture&lt;/li&gt;
&lt;li&gt;Predictable structure&lt;/li&gt;
&lt;li&gt;Separation of concerns&lt;/li&gt;
&lt;li&gt;Strong conventions
Next.js (especially App Router) provides powerful primitives, but it does NOT enforce architecture, that’s your responsibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide gives you a production-grade blueprint.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Architecture Matters
&lt;/h2&gt;

&lt;p&gt;At scale, poor architecture leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tight coupling between components&lt;/li&gt;
&lt;li&gt;Duplicate logic across features&lt;/li&gt;
&lt;li&gt;Slow builds &amp;amp; performance bottlenecks&lt;/li&gt;
&lt;li&gt;Difficult onboarding for new developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good architecture enables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Independent feature development&lt;/li&gt;
&lt;li&gt;Faster debugging&lt;/li&gt;
&lt;li&gt;Better scalability&lt;/li&gt;
&lt;li&gt;Easier refactoring&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Core Principles of Scalable Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Separation of Concerns&lt;/strong&gt;&lt;br&gt;
Divide responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI → components&lt;/li&gt;
&lt;li&gt;Logic → hooks/services&lt;/li&gt;
&lt;li&gt;Data → API layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Feature Isolation&lt;/strong&gt;&lt;br&gt;
Each feature should be self-contained.&lt;br&gt;
Think like mini-apps inside your app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Single Responsibility Principle&lt;/strong&gt;&lt;br&gt;
Each file/module should do one thing well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Dependency Direction&lt;/strong&gt;&lt;br&gt;
Components depend on hooks&lt;br&gt;
Hooks depend on services&lt;br&gt;
Services depend on APIs&lt;br&gt;
NOT the other way around.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Scalability First Mindset&lt;/strong&gt;&lt;br&gt;
Design for scale even if you’re small today.&lt;/p&gt;
&lt;h2&gt;
  
  
  Advanced Folder Structure (Enterprise-Level)
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
│
├── app/                         # Next.js App Router
│   ├── (public)/
│   ├── (auth)/
│   ├── dashboard/
│   │   ├── layout.tsx
│   │   ├── page.tsx
│
├── features/                    # Feature modules (CORE)
│   ├── auth/
│   │   ├── components/
│   │   ├── hooks/
│   │   ├── services/
│   │   ├── api/
│   │   ├── store/
│   │   └── types.ts
│   │
│   ├── products/
│   ├── orders/
│   └── users/
│
├── shared/                      # Cross-feature reusable code
│   ├── components/
│   ├── hooks/
│   ├── utils/
│   └── constants/
│
├── core/                        # App-level logic
│   ├── config/
│   ├── providers/
│   ├── middleware/
│   └── guards/
│
├── services/                    # Global services (rare)
├── lib/                         # Low-level utilities
├── types/                       # Global types
├── styles/
└── tests/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;“Fetching data is easy. Fetching it efficiently is architecture.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;&lt;br&gt;
Avoid “global chaos” folders like components/ for everything&lt;br&gt;
Prefer feature-based grouping&lt;/p&gt;
&lt;h2&gt;
  
  
  Architectural Patterns (Deep Dive)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Feature-Based Architecture (MOST IMPORTANT)&lt;/strong&gt;&lt;br&gt;
Each feature owns:&lt;br&gt;
UI&lt;br&gt;
logic&lt;br&gt;
API calls&lt;br&gt;
state&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;features/products/
    components/
    hooks/
    services/
    store/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Layered Architecture&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UI Layer (Components)
↓
Hooks Layer (Business Logic)
↓
Service Layer (API Calls)
↓
API Layer (External systems)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Server vs Client Component Strategy&lt;/strong&gt;&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%2Fx1ukizc2nbaa3674k6id.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%2Fx1ukizc2nbaa3674k6id.png" alt=" " width="631" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Server Component&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&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;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;getProducts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProductsClient&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Smart vs Dumb Components&lt;/strong&gt;&lt;br&gt;
Smart → fetch + logic&lt;br&gt;
Dumb → UI only&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Composition Pattern&lt;/strong&gt;&lt;br&gt;
Avoid inheritance. Use composition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProductInfo&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  State Management at Scale
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use global state&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static data&lt;/li&gt;
&lt;li&gt;Server-fetched data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Recommended Strategy&lt;/strong&gt;&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%2Fubva1g9kclr948nq6nhm.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%2Fubva1g9kclr948nq6nhm.png" alt=" " width="633" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example (Zustand Advanced)&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="k"&gt;import&lt;/span&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zustand&lt;/span&gt;&lt;span class="dl"&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;useCartStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kd"&gt;set&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="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&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="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
  &lt;span class="na"&gt;clearCart&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="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;items&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Data Fetching &amp;amp; API Layer Design
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bad Practice&lt;/strong&gt;&lt;br&gt;
Calling fetch directly in components everywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good Practice&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;features&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="o"&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;productService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&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;getProducts&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="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;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;/api/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;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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;“Every unnecessary render is a tax on your use.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Caching Strategy&lt;/strong&gt;&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%2Fky5ilifqh69r9fxw1xo7.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%2Fky5ilifqh69r9fxw1xo7.png" alt=" " width="636" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication &amp;amp; Authorization Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended Setup&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Middleware for route protection&lt;/li&gt;
&lt;li&gt;Server-side session validation&lt;/li&gt;
&lt;li&gt;Role-based access
Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// middleware.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;middleware&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="p"&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&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;token&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="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;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Performance Optimization (Advanced)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Techniques&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code splitting (dynamic imports)&lt;/li&gt;
&lt;li&gt;Partial hydration&lt;/li&gt;
&lt;li&gt;Edge rendering&lt;/li&gt;
&lt;li&gt;Image optimization&lt;/li&gt;
&lt;li&gt;Memoization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&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;Chart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Chart&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="na"&gt;ssr&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Error Handling &amp;amp; Logging
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Centralized Error Handling&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleError&lt;/span&gt; &lt;span class="o"&gt;=&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="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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Logging Tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sentry&lt;/li&gt;
&lt;li&gt;LogRocket&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing Strategy (Production-Ready)
&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%2F73xtlkanvzvmdagm2b77.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%2F73xtlkanvzvmdagm2b77.png" alt=" " width="630" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;adds item to cart&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useCartStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dev Experience &amp;amp; Code Quality
&lt;/h2&gt;

&lt;p&gt;ESLint + Prettier&lt;br&gt;
Husky (pre-commit hooks)&lt;br&gt;
Strict TypeScript&lt;br&gt;
Absolute imports (@/features/...)&lt;/p&gt;
&lt;h2&gt;
  
  
  Deployment &amp;amp; Infrastructure Strategy
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended Stack&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hosting → Vercel&lt;/li&gt;
&lt;li&gt;DB → PostgreSQL&lt;/li&gt;
&lt;li&gt;CDN → Cloudflare&lt;/li&gt;
&lt;li&gt;Monitoring → Sentry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Scaling Tips&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Edge Functions&lt;/li&gt;
&lt;li&gt;Optimize bundle size&lt;/li&gt;
&lt;li&gt;Enable caching&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Real-World Example (Enterprise Dashboard)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;features/dashboard/
   components/
      StatsCard.tsx
   hooks/
      useStats.ts
   services/
      dashboardService.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchStats&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="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;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;/api/stats&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hook&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useStats&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setStats&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetchStats&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setStats&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Component&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StatsCard&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&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;totalUsers&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Page&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DashboardPage&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;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStats&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;stats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StatsCard&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next.js App Router defaults to Server Components.Source: &lt;a href="https://nextjs.org/docs/app/building-your-application/rendering/server-components" rel="noopener noreferrer"&gt;https://nextjs.org/docs/app/building-your-application/rendering/server-components&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Middleware runs at the Edge.Source: &lt;a href="https://nextjs.org/docs/pages/api-reference/file-conventions/middleware" rel="noopener noreferrer"&gt;https://nextjs.org/docs/pages/api-reference/file-conventions/middleware&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;File-based routing reduces ~40% boilerplate.Source: &lt;a href="https://nextjs.org/docs/app/building-your-application/routing" rel="noopener noreferrer"&gt;https://nextjs.org/docs/app/building-your-application/routing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Built-in optimizations replace many libraries.Source: &lt;a href="https://nextjs.org/docs/architecture" rel="noopener noreferrer"&gt;https://nextjs.org/docs/architecture&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ISR allows hybrid static + dynamic pages.Source: &lt;a href="https://nextjs.org/docs/pages/building-your-application/rendering/incremental-static-regeneration" rel="noopener noreferrer"&gt;https://nextjs.org/docs/pages/building-your-application/rendering/incremental-static-regeneration&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next.js is one of the fastest-growing React frameworks and is widely adopted for production-grade applications.
Source: &lt;a href="https://nextjs.org/showcase" rel="noopener noreferrer"&gt;https://nextjs.org/showcase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Next.js has 120,000+ stars on GitHub, reflecting its strong developer adoption and community support.
Source: &lt;a href="https://github.com/vercel/next.js" rel="noopener noreferrer"&gt;https://github.com/vercel/next.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;According to the State of JS survey, Next.js consistently ranks among the top frameworks in developer satisfaction and usage.
Source: &lt;a href="https://stateofjs.com/" rel="noopener noreferrer"&gt;https://stateofjs.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Vercel, the company behind Next.js, serves billions of requests per week across applications deployed on its platform.
Source: &lt;a href="https://vercel.com/customers" rel="noopener noreferrer"&gt;https://vercel.com/customers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Next.js enables hybrid rendering (SSR, SSG, ISR), which improves performance and scalability for modern web applications.
Source: &lt;a href="https://nextjs.org/docs/pages/building-your-application/rendering" rel="noopener noreferrer"&gt;https://nextjs.org/docs/pages/building-your-application/rendering&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;File-based routing in Next.js simplifies development by automatically mapping files to routes, reducing manual configuration.
Source: &lt;a href="https://nextjs.org/docs/app/building-your-application/routing" rel="noopener noreferrer"&gt;https://nextjs.org/docs/app/building-your-application/routing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ’s
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1. Is Redux necessary?&lt;/strong&gt;&lt;br&gt;
No. Use Zustand unless you need complex workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2. How to organize large teams?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Feature ownership&lt;/li&gt;
&lt;li&gt;Code reviews&lt;/li&gt;
&lt;li&gt;Clear folder structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Q3. Should I use monorepo?&lt;/strong&gt;&lt;br&gt;
Yes, for multi-app systems (Nx / Turborepo).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4. Where to keep reusable components?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;shared/components&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5. What is the biggest mistake?&lt;/strong&gt;&lt;br&gt;
Mixing everything in global folders.&lt;/p&gt;

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

&lt;p&gt;Scaling a Next.js application is more about architecture than code. The difference between a messy app and a scalable system lies in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structure&lt;/li&gt;
&lt;li&gt;Discipline&lt;/li&gt;
&lt;li&gt;Consistency
By following feature-based design, layered architecture, and modern Next.js patterns, you can build applications that scale effortlessly with both users and teams.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About the Author:&lt;em&gt;Mayank is a web developer at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;, building scalable apps with PHP, Node.js &amp;amp; React. Sharing ideas, code, and creativity.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>ELK Stack Setup for Centralized Log Management &amp; Monitoring</title>
      <dc:creator>Rajan Vavadia</dc:creator>
      <pubDate>Wed, 08 Apr 2026 11:42:01 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/elk-stack-setup-for-centralized-log-management-monitoring-11l0</link>
      <guid>https://dev.to/addwebsolutionpvtltd/elk-stack-setup-for-centralized-log-management-monitoring-11l0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“The goal is to turn data into information, and information into insight.” - Carly Fiorina&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Stage 1: Elasticsearch - The Search &amp;amp; Storage Engine&lt;/li&gt;
&lt;li&gt;Stage 2: Logstash - The Data Processing Pipeline&lt;/li&gt;
&lt;li&gt;Stage 3: Kibana - The Visualization Layer&lt;/li&gt;
&lt;li&gt;Stage 4: Filebeat - The Lightweight Log Shipper&lt;/li&gt;
&lt;li&gt;Connecting the Pieces - End-to-End Data Flow&lt;/li&gt;
&lt;li&gt;Practical Setup (Step-by-step)&lt;/li&gt;
&lt;li&gt;Troubleshooting Common Issues&lt;/li&gt;
&lt;li&gt;Quotes&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Key Takeaways&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;When your application runs on a single server, tailing a log file is enough. When it runs across multiple servers, containers, or microservices - you need centralized logging. Scattered logs across dozens of servers make debugging slow, error correlation impossible, and incident response reactive instead of proactive.&lt;/p&gt;

&lt;p&gt;This guide walks through setting up a production-ready ELK stack (Elasticsearch, Logstash, Kibana) with Filebeat for centralized log collection, processing, and visualization. The setup covers a real-world scenario: a Java Spring Boot application running on one server, with the ELK stack on a separate server.&lt;/p&gt;

&lt;p&gt;The approach uses a &lt;strong&gt;four-component architecture:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filebeat (Application Server): Lightweight agent that tails log files and ships them to Logstash.&lt;/li&gt;
&lt;li&gt;Logstash (ELK Server): Receives raw logs, parses and transforms them, and forwards structured data to Elasticsearch.&lt;/li&gt;
&lt;li&gt;Elasticsearch (ELK Server): Stores, indexes, and makes logs searchable in near real-time.&lt;/li&gt;
&lt;li&gt;Kibana (ELK Server): Web UI for searching, visualizing, and building dashboards from log data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why centralized logging?&lt;/strong&gt;&lt;br&gt;
Manually SSH-ing into each server and grepping through log files does not scale. Centralized logging solves this by aggregating all logs into a single searchable location. &lt;br&gt;
You get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single pane of glass for all application and infrastructure logs.&lt;/li&gt;
&lt;li&gt;Real-time search across millions of log entries in milliseconds.&lt;/li&gt;
&lt;li&gt;Correlation of events across services and servers by timestamp.&lt;/li&gt;
&lt;li&gt;Alerting on error patterns before users report issues.&lt;/li&gt;
&lt;li&gt;Retention and compliance with configurable index lifecycle policies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Component Responsibilities&lt;/strong&gt;&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%2Fzp9p4c79403j4tu2xf2q.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%2Fzp9p4c79403j4tu2xf2q.png" alt=" " width="537" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why separate servers?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Resource isolation:&lt;/strong&gt; Elasticsearch is memory-hungry. Running it on the application server competes with your app for RAM and CPU.&lt;br&gt;
&lt;strong&gt;- Independent scaling:&lt;/strong&gt; You can scale the ELK server (more RAM, bigger disk) without touching production application servers.&lt;br&gt;
&lt;strong&gt;- Security boundary:&lt;/strong&gt; The ELK server can sit in a private subnet, accessible only to internal services and authorized users.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Stage 1: Elasticsearch - The Search &amp;amp; Storage Engine
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;2.1 What is Elasticsearch?&lt;/strong&gt;&lt;br&gt;
Elasticsearch is a distributed search and analytics engine built on Apache Lucene. In the ELK stack, it serves as the storage and search backend - every log line that Logstash processes ends up as a document in an Elasticsearch index.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.2 Installation&lt;/strong&gt;&lt;br&gt;
Import the Elasticsearch GPG key&lt;br&gt;
wget -qO - &lt;a href="https://artifacts.elastic.co/GPG-KEY-elasticsearch" rel="noopener noreferrer"&gt;https://artifacts.elastic.co/GPG-KEY-elasticsearch&lt;/a&gt; | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg&lt;/p&gt;

&lt;p&gt;Add the APT repository&lt;br&gt;
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] &lt;a href="https://artifacts.elastic.co/packages/8.x/apt" rel="noopener noreferrer"&gt;https://artifacts.elastic.co/packages/8.x/apt&lt;/a&gt; stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list&lt;/p&gt;

&lt;p&gt;Install Elasticsearch&lt;br&gt;
sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y elasticsearch&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.3 Configuration&lt;/strong&gt;&lt;br&gt;
The main configuration file is /etc/elasticsearch/elasticsearch.yml:&lt;br&gt;
Cluster and node identity&lt;br&gt;
cluster.name: my-cluster&lt;br&gt;
node.name: node-1&lt;/p&gt;

&lt;p&gt;Data and log paths&lt;br&gt;
path.data: /var/lib/elasticsearch&lt;br&gt;
path.logs: /var/log/elasticsearch&lt;/p&gt;

&lt;p&gt;Network - bind to all interfaces for external access&lt;br&gt;
network.host: 0.0.0.0&lt;br&gt;
http.host: 0.0.0.0&lt;/p&gt;

&lt;p&gt;Discovery - single node (no cluster formation)&lt;br&gt;
discovery.type: single-node&lt;/p&gt;

&lt;p&gt;Security - disable for internal/dev setups&lt;br&gt;
xpack.security.enabled: false&lt;br&gt;
xpack.security.enrollment.enabled: true&lt;br&gt;
xpack.security.http.ssl:&lt;br&gt;
  enabled: false&lt;br&gt;
xpack.security.transport.ssl:&lt;br&gt;
  enabled: false&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration settings explained:&lt;/strong&gt;&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%2Fem1va7kcqe4w5mfpga6u.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%2Fem1va7kcqe4w5mfpga6u.png" alt=" " width="535" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security note:&lt;/strong&gt; xpack.security.enabled: false is acceptable for internal/development setups behind a firewall. For production environments exposed to the internet, always enable security with TLS certificates and user authentication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.4 Start and Enable&lt;/strong&gt;&lt;br&gt;
sudo systemctl daemon-reload&lt;br&gt;
sudo systemctl enable elasticsearch&lt;br&gt;
sudo systemctl start elasticsearch&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.5 Verify&lt;/strong&gt;&lt;br&gt;
curl &lt;a href="http://localhost:9200" rel="noopener noreferrer"&gt;http://localhost:9200&lt;/a&gt;&lt;br&gt;
Expected response:&lt;br&gt;
{&lt;br&gt;
  "name": "node-1",&lt;br&gt;
  "cluster_name": "my-cluster",&lt;br&gt;
  "version": {&lt;br&gt;
    "number": "8.x.x"&lt;br&gt;
  },&lt;br&gt;
  "tagline": "You Know, for Search"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.6 Memory Considerations&lt;/strong&gt;&lt;br&gt;
Elasticsearch defaults to a 1GB heap (-Xms1g -Xmx1g). For production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set heap to 50% of available RAM, but never more than 31GB (to stay within compressed OOPs).&lt;/li&gt;
&lt;li&gt;Edit /etc/elasticsearch/jvm.options.d/heap.options:
-Xms2g
-Xmx2g&lt;/li&gt;
&lt;li&gt;Ensure the system has enough RAM for both the JVM heap and filesystem cache (Lucene relies heavily on OS page cache).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  3. Stage 2: Logstash - The Data Processing Pipeline
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;3.1 What is Logstash?&lt;/strong&gt;&lt;br&gt;
Logstash is a server-side data processing pipeline that ingests data from multiple sources, transforms it, and sends it to Elasticsearch. It sits between Filebeat and Elasticsearch, adding structure to raw log lines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.2 Installation&lt;/strong&gt;&lt;br&gt;
sudo apt-get install -y logstash&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.3 Pipeline Configuration&lt;/strong&gt;&lt;br&gt;
Logstash pipelines are defined in /etc/logstash/conf.d/. Each pipeline has three sections: input, filter, and output.&lt;br&gt;
Create /etc/logstash/conf.d/boardgame.conf:&lt;br&gt;
input {&lt;br&gt;
  beats {&lt;br&gt;
    port =&amp;gt; 5044&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;filter {&lt;br&gt;
  #Parse Spring Boot log format&lt;br&gt;
  grok {&lt;br&gt;
    match =&amp;gt; { "message" =&amp;gt; "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:loglevel} %{GREEDYDATA:logmessage}" }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;output {&lt;br&gt;
  elasticsearch {&lt;br&gt;
    hosts =&amp;gt; ["localhost:9200"]&lt;br&gt;
    index =&amp;gt; "boardgame-logs-%{+YYYY.MM.dd}"&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
Pipeline sections explained:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input - Where data comes from:&lt;/strong&gt;&lt;br&gt;
input {&lt;br&gt;
  beats {&lt;br&gt;
    port =&amp;gt; 5044&lt;br&gt;
  }&lt;br&gt;
}&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%2Fwxark7w6og256clyj5mj.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%2Fwxark7w6og256clyj5mj.png" alt=" " width="536" height="163"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filter - How data is transformed:&lt;/strong&gt;&lt;br&gt;
filter {&lt;br&gt;
  grok {&lt;br&gt;
    match =&amp;gt; { "message" =&amp;gt; "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:loglevel} %{GREEDYDATA:logmessage}" }&lt;br&gt;
  }&lt;br&gt;
}&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%2Ften9gk99e9hu2slwlwce.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%2Ften9gk99e9hu2slwlwce.png" alt=" " width="538" height="163"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The grok filter parses unstructured log lines into structured fields (timestamp, loglevel, logmessage). This enables filtering by log level in Kibana (e.g., show only ERROR logs).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output - Where data goes:&lt;/strong&gt;&lt;br&gt;
output {&lt;br&gt;
  elasticsearch {&lt;br&gt;
    hosts =&amp;gt; ["localhost:9200"]&lt;br&gt;
    index =&amp;gt; "boardgame-logs-%{+YYYY.MM.dd}"&lt;br&gt;
  }&lt;br&gt;
}&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%2Fbf73dgxhsyznncijxevd.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%2Fbf73dgxhsyznncijxevd.png" alt=" " width="536" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why daily indices?&lt;/strong&gt; Daily indices make retention management simple - delete old indices by date. They also improve search performance because Elasticsearch can skip entire indices when querying a specific time range.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.4 Start and Enable&lt;/strong&gt;&lt;br&gt;
sudo systemctl daemon-reload&lt;br&gt;
sudo systemctl enable logstash&lt;br&gt;
sudo systemctl start logstash&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.5 Verify&lt;/strong&gt;&lt;br&gt;
Check if Logstash is listening on port 5044&lt;br&gt;
sudo ss -tlnp | grep 5044&lt;/p&gt;

&lt;p&gt;Check Logstash logs for pipeline startup&lt;br&gt;
sudo journalctl -u logstash --no-pager -n 20&lt;br&gt;
Look for: Pipeline started {"pipeline.id"=&amp;gt;"main"} in the logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Stage 3: Kibana - The Visualization Layer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;4.1 What is Kibana?&lt;/strong&gt;&lt;br&gt;
Kibana is the web interface for the ELK stack. It connects to Elasticsearch and provides tools for searching logs (Discover), building visualizations (charts, graphs, maps), and creating dashboards for real-time monitoring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.2 Installation&lt;/strong&gt;&lt;br&gt;
sudo apt-get install -y kibana&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.3 Configuration&lt;/strong&gt;&lt;br&gt;
Edit /etc/kibana/kibana.yml:&lt;br&gt;
Bind to all interfaces for external access&lt;br&gt;
server.host: "0.0.0.0"&lt;/p&gt;

&lt;p&gt;Connect to Elasticsearch over plain HTTP&lt;br&gt;
elasticsearch.hosts: ["&lt;a href="http://localhost:9200%22" rel="noopener noreferrer"&gt;http://localhost:9200"&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Critical configuration points:&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%2Ft31gdko0evuu2z2ewcfi.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%2Ft31gdko0evuu2z2ewcfi.png" alt=" " width="536" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common pitfall:&lt;/strong&gt; If Elasticsearch has xpack.security.http.ssl.enabled: false but Kibana is configured with https:// in elasticsearch.hosts, Kibana will fail to connect with Unable to retrieve version information from Elasticsearch. Always match the protocol.&lt;/p&gt;

&lt;p&gt;Settings to remove or comment out when SSL is disabled:&lt;br&gt;
Comment out or remove these lines&lt;br&gt;
elasticsearch.ssl.certificateAuthorities: [/path/to/ca.crt]&lt;br&gt;
elasticsearch.username: "kibana_system"&lt;br&gt;
elasticsearch.password: "pass"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.4 Start and Enable&lt;/strong&gt;&lt;br&gt;
sudo systemctl daemon-reload&lt;br&gt;
sudo systemctl enable kibana&lt;br&gt;
sudo systemctl start kibana&lt;/p&gt;

&lt;p&gt;Kibana takes 30–60 seconds to fully initialize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.5 Verify&lt;/strong&gt;&lt;br&gt;
curl &lt;a href="http://localhost:5601/api/status" rel="noopener noreferrer"&gt;http://localhost:5601/api/status&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Expected: {"status":{"overall":{"level":"available"}}} - the level should be available, not unavailable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.6 Create a Data View&lt;/strong&gt;&lt;br&gt;
Once data is flowing, create a data view so Kibana knows which indices to query:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open http://:5601 in a browser.&lt;/li&gt;
&lt;li&gt;Navigate to Stack Management &amp;gt; Data Views (under Kibana section).&lt;/li&gt;
&lt;li&gt;Click Create data view.&lt;/li&gt;
&lt;li&gt;Fill in the fields:&lt;/li&gt;
&lt;/ol&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%2F9qn4bpi9xpwcqc02w2pt.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%2F9qn4bpi9xpwcqc02w2pt.png" alt=" " width="535" height="108"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now go to Discover (under Analytics) to search and explore your logs.&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%2Fc9jbbxazfjeo9xc8w6vk.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%2Fc9jbbxazfjeo9xc8w6vk.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.7 AWS Security Group&lt;/strong&gt;&lt;br&gt;
If running on AWS EC2, ensure the security group allows inbound traffic:&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%2F0je9eq8pgadlzacfacjo.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%2F0je9eq8pgadlzacfacjo.png" alt=" " width="536" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Never expose port 9200 to the public internet unless Elasticsearch security is enabled with TLS and authentication.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Logs are the immune system of your infrastructure - they tell you when something is wrong before it becomes a crisis.” - DevOps principle&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. Stage 4: Filebeat - The Lightweight Log Shipper
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;5.1 What is Filebeat?&lt;/strong&gt;&lt;br&gt;
Filebeat is a lightweight log shipper that runs on the application server. It tails log files, handles log rotation, tracks read positions (so it never sends duplicate lines), and ships logs to Logstash or Elasticsearch with minimal resource overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.2 Why Filebeat instead of sending directly to Logstash?&lt;/strong&gt;&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%2Faph4qwaku3cx7i77kfpl.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%2Faph4qwaku3cx7i77kfpl.png" alt=" " width="537" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Filebeat decouples your application from the logging pipeline. If Logstash or Elasticsearch goes down, Filebeat queues events and retries automatically. Your application keeps writing to its log file without interruption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.3 Installation (on the Application Server)&lt;/strong&gt;&lt;br&gt;
Use the same Elastic repository&lt;br&gt;
sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y filebeat&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.4 Configuration&lt;/strong&gt;&lt;br&gt;
Edit /etc/filebeat/filebeat.yml:&lt;br&gt;
filebeat.inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;type: log
enabled: true
paths:

&lt;ul&gt;
&lt;li&gt;/home/ubuntu/Boardgame/target/app.log
multiline.pattern: '^\d{4}-\d{2}-\d{2}'
multiline.negate: true
multiline.match: after&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;output.logstash:&lt;br&gt;
  hosts: [":5044"]&lt;/p&gt;

&lt;p&gt;processors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add_host_metadata:
  when.not.contains.tags: forwarded&lt;/li&gt;
&lt;li&gt;add_cloud_metadata: ~&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;logging.level: info&lt;/p&gt;

&lt;p&gt;Configuration explained:&lt;br&gt;
Input section:&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%2Fsh55ewofbyjh7ybk6wzp.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%2Fsh55ewofbyjh7ybk6wzp.png" alt=" " width="540" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Multiline settings (critical for Java/Spring Boot stack traces):&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%2Fz47xuf0vcqg9zs5pn9lj.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%2Fz47xuf0vcqg9zs5pn9lj.png" alt=" " width="539" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This ensures that a multi-line Java stack trace is treated as a single log event, not dozens of separate lines:&lt;br&gt;
2026-03-11 06:37:55 ERROR Something went wrong&lt;br&gt;
java.lang.NullPointerException&lt;br&gt;
    at com.example.Service.process(Service.java:42)&lt;br&gt;
    at com.example.Controller.handle(Controller.java:15)&lt;br&gt;
Without multiline config, each line of the stack trace becomes a separate Elasticsearch document - making it impossible to correlate errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output section:&lt;/strong&gt;&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%2Fr3ikg4a1gvaosipkbc0y.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%2Fr3ikg4a1gvaosipkbc0y.png" alt=" " width="536" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Processors:&lt;/strong&gt;&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%2F3fnzz2za241yhshna9z1.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%2F3fnzz2za241yhshna9z1.png" alt=" " width="536" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;YAML formatting rules (common source of errors):&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%2Fcl5wkwylunhomvhmstmr.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%2Fcl5wkwylunhomvhmstmr.png" alt=" " width="537" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.5 Start and Enable&lt;/strong&gt;&lt;br&gt;
Clear old registry to re-read files from the beginning&lt;br&gt;
sudo rm -rf /var/lib/filebeat/registry&lt;/p&gt;

&lt;p&gt;sudo systemctl daemon-reload&lt;br&gt;
sudo systemctl enable filebeat&lt;br&gt;
sudo systemctl start filebeat&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.6 Verify&lt;/strong&gt;&lt;br&gt;
Check Filebeat status&lt;br&gt;
sudo systemctl status filebeat&lt;/p&gt;

&lt;p&gt;Check logs - look for "Harvester started"&lt;br&gt;
sudo journalctl -u filebeat --no-pager -n 20&lt;br&gt;
Key indicators in the logs:&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%2Fj5zmhi84e6as4n5e0j18.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%2Fj5zmhi84e6as4n5e0j18.png" alt=" " width="537" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Connecting the Pieces - End-to-End Data Flow
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;6.1 The Complete Pipeline&lt;/strong&gt;&lt;br&gt;
[Spring Boot App]&lt;br&gt;
       │&lt;br&gt;
       │ writes logs to disk&lt;br&gt;
       ▼&lt;br&gt;
[/home/ubuntu/Boardgame/target/app.log]&lt;br&gt;
       │&lt;br&gt;
       │ Filebeat tails the file&lt;br&gt;
       ▼&lt;br&gt;
[Filebeat] ──── port 5044 ────► [Logstash]&lt;br&gt;
                                     │&lt;br&gt;
                                     │ grok filter parses log lines&lt;br&gt;
                                     ▼&lt;br&gt;
                              [Elasticsearch]&lt;br&gt;
                              index: boardgame-logs-2026.03.11&lt;br&gt;
                                     │&lt;br&gt;
                                     │ Kibana queries the index&lt;br&gt;
                                     ▼&lt;br&gt;
                                 [Kibana]&lt;br&gt;
                              http://:5601&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%2Fmf618ruhvk1s0kvzwn6f.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%2Fmf618ruhvk1s0kvzwn6f.png" alt=" " width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.2 Verifying Each Link&lt;/strong&gt;&lt;br&gt;
Test each component in order, from bottom to top:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Elasticsearch is running and accessible&lt;br&gt;
curl &lt;a href="http://localhost:9200" rel="noopener noreferrer"&gt;http://localhost:9200&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Logstash is listening for Beats input&lt;br&gt;
sudo ss -tlnp | grep 5044&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kibana can reach Elasticsearch&lt;br&gt;
curl &lt;a href="http://localhost:5601/api/status" rel="noopener noreferrer"&gt;http://localhost:5601/api/status&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Filebeat can reach Logstash (from application server)&lt;br&gt;
telnet  5044&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data is actually in Elasticsearch&lt;br&gt;
curl &lt;a href="http://localhost:9200/_cat/indices?v" rel="noopener noreferrer"&gt;http://localhost:9200/_cat/indices?v&lt;/a&gt; | grep boardgame&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check document count&lt;br&gt;
curl &lt;a href="http://localhost:9200/boardgame-logs-*/_count" rel="noopener noreferrer"&gt;http://localhost:9200/boardgame-logs-*/_count&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  7. Practical Setup (Step-by-step)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;7.1 Server Requirements&lt;/strong&gt;&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%2Fo5klb3utps0mw74tahu2.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%2Fo5klb3utps0mw74tahu2.png" alt=" " width="535" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.2 ELK Server Setup (in order)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Step 1: Add Elastic repository&lt;br&gt;
wget -qO - &lt;a href="https://artifacts.elastic.co/GPG-KEY-elasticsearch" rel="noopener noreferrer"&gt;https://artifacts.elastic.co/GPG-KEY-elasticsearch&lt;/a&gt; | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg&lt;br&gt;
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] &lt;a href="https://artifacts.elastic.co/packages/8.x/apt" rel="noopener noreferrer"&gt;https://artifacts.elastic.co/packages/8.x/apt&lt;/a&gt; stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list&lt;br&gt;
sudo apt-get update&lt;/p&gt;

&lt;p&gt;Step 2: Install all three components&lt;br&gt;
sudo apt-get install -y elasticsearch logstash kibana&lt;/p&gt;

&lt;p&gt;Step 3: Configure Elasticsearch&lt;br&gt;
sudo nano /etc/elasticsearch/elasticsearch.yml&lt;br&gt;
Set: network.host: 0.0.0.0&lt;br&gt;
Set: discovery.type: single-node&lt;br&gt;
Set: xpack.security.enabled: false&lt;br&gt;
Set: xpack.security.http.ssl.enabled: false&lt;br&gt;
Set: xpack.security.transport.ssl.enabled: false&lt;/p&gt;

&lt;p&gt;Step 4: Configure Logstash pipeline&lt;br&gt;
sudo nano /etc/logstash/conf.d/boardgame.conf&lt;br&gt;
Add input (beats, port 5044), filter (grok), output (elasticsearch)&lt;/p&gt;

&lt;p&gt;Step 5: Configure Kibana&lt;br&gt;
sudo nano /etc/kibana/kibana.yml&lt;br&gt;
Set: server.host: "0.0.0.0"&lt;br&gt;
Set: elasticsearch.hosts: ["&lt;a href="http://localhost:9200%22" rel="noopener noreferrer"&gt;http://localhost:9200"&lt;/a&gt;]&lt;br&gt;
Remove/comment any SSL certificate lines&lt;/p&gt;

&lt;p&gt;Step 6: Start services&lt;br&gt;
sudo systemctl enable elasticsearch logstash kibana&lt;br&gt;
sudo systemctl start elasticsearch logstash kibana&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.3 Application Server Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Step 1: Install Filebeat&lt;br&gt;
sudo apt-get install -y filebeat&lt;/p&gt;

&lt;p&gt;Step 2: Configure Filebeat&lt;br&gt;
sudo nano /etc/filebeat/filebeat.yml&lt;br&gt;
Replace entire file with clean config (see Section 6.4)&lt;/p&gt;

&lt;p&gt;Step 3: Clear registry and start&lt;br&gt;
sudo rm -rf /var/lib/filebeat/registry&lt;br&gt;
sudo systemctl enable filebeat&lt;br&gt;
sudo systemctl start filebeat&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.4 Kibana Data View Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Verify data arrived in Elasticsearch&lt;br&gt;
curl http://:9200/_cat/indices?v | grep boardgame&lt;br&gt;
Then in the Kibana UI: 1. Stack Management &amp;gt; Data Views &amp;gt; Create data view 2. Name: Boardgame Logs, Index pattern: boardgame-logs-*, Timestamp: @timestamp 3. Save data view to Kibana 4. Go to Discover to explore your logs&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.5 Optional: Index Lifecycle Management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For production, configure automatic index cleanup to prevent disk from filling up:&lt;br&gt;
Create an ILM policy that deletes indices older than 30 days&lt;br&gt;
curl -X PUT "&lt;a href="http://localhost:9200/_ilm/policy/boardgame-logs-policy" rel="noopener noreferrer"&gt;http://localhost:9200/_ilm/policy/boardgame-logs-policy&lt;/a&gt;" -H 'Content-Type: application/json' -d'&lt;br&gt;
{&lt;br&gt;
  "policy": {&lt;br&gt;
    "phases": {&lt;br&gt;
      "hot": {&lt;br&gt;
        "actions": {&lt;br&gt;
          "rollover": {&lt;br&gt;
            "max_size": "5gb",&lt;br&gt;
            "max_age": "1d"&lt;br&gt;
          }&lt;br&gt;
        }&lt;br&gt;
      },&lt;br&gt;
      "delete": {&lt;br&gt;
        "min_age": "30d",&lt;br&gt;
        "actions": {&lt;br&gt;
          "delete": {}&lt;br&gt;
        }&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}'&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Troubleshooting Common Issues
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;8.1 Kibana shows “Unable to retrieve version information from Elasticsearch”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cause: Protocol mismatch - Kibana is using https:// but Elasticsearch has SSL disabled.&lt;br&gt;
Fix:&lt;br&gt;
Check current Kibana config&lt;br&gt;
sudo grep "elasticsearch.hosts" /etc/kibana/kibana.yml&lt;/p&gt;

&lt;p&gt;Fix: change https to http&lt;br&gt;
elasticsearch.hosts: ["&lt;a href="http://localhost:9200%22" rel="noopener noreferrer"&gt;http://localhost:9200"&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Comment out any SSL certificate lines&lt;br&gt;
elasticsearch.ssl.certificateAuthorities: [...]&lt;/p&gt;

&lt;p&gt;sudo systemctl restart kibana&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8.2 Filebeat shows harvester.open_files: 0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cause: Filebeat config is malformed (duplicate sections, wrong indentation, or double-quoted regex).&lt;br&gt;
Fix: - Ensure filebeat.yml has no duplicate top-level keys. - Use single quotes for multiline.pattern (YAML treats \d in double quotes as an escape sequence). - Top-level keys (filebeat.inputs:, output.logstash:, processors:) must start at column 0.&lt;br&gt;
Validate the config&lt;br&gt;
sudo filebeat test config -c /etc/filebeat/filebeat.yml&lt;/p&gt;

&lt;p&gt;Clear registry and restart&lt;br&gt;
sudo rm -rf /var/lib/filebeat/registry&lt;br&gt;
sudo systemctl restart filebeat&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8.3 No boardgame-logs-* indices in Elasticsearch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cause: Filebeat cannot reach Logstash on port 5044.&lt;br&gt;
Fix:&lt;br&gt;
From the application server, test connectivity&lt;br&gt;
telnet  5044&lt;/p&gt;

&lt;p&gt;If connection refused - open port 5044 in the ELK server's security group&lt;br&gt;
If connection times out - check if Logstash is running&lt;br&gt;
sudo systemctl status logstash&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%2Fktjli79a9bl69xpo0mfr.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%2Fktjli79a9bl69xpo0mfr.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&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/..." 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/..." alt="Uploading image" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8.4 Kibana Data View shows “No data streams, indices, or index aliases match”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cause: No data has been ingested yet, or the index pattern is wrong.&lt;br&gt;
Fix:&lt;br&gt;
List all indices&lt;br&gt;
curl &lt;a href="http://localhost:9200/_cat/indices?v" rel="noopener noreferrer"&gt;http://localhost:9200/_cat/indices?v&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check the exact index name and match your pattern accordingly&lt;br&gt;
If index is "boardgame-logs-2026.03.11", pattern should be "boardgame-logs-*"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8.5 Logstash is running but not receiving data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cause: Logstash pipeline failed to start, or the config file has syntax errors.&lt;br&gt;
Fix:&lt;br&gt;
Test the Logstash config&lt;br&gt;
sudo /usr/share/logstash/bin/logstash --config.test_and_exit -f /etc/logstash/conf.d/&lt;/p&gt;

&lt;p&gt;Check Logstash logs&lt;br&gt;
sudo journalctl -u logstash --no-pager -n 30&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“You can’t manage what you can’t measure.” - Peter Drucker&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  9. FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1. Why use the ELK stack instead of cloud-native logging (CloudWatch, Stackdriver)?&lt;/strong&gt; &lt;br&gt;
ELK gives you full control over data retention, parsing rules, and costs. Cloud logging services charge per GB ingested, which becomes expensive at scale. ELK is free (open-source) - you only pay for the infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2. Why Filebeat instead of sending logs directly from the application?&lt;/strong&gt; &lt;br&gt;
Filebeat decouples your application from the logging pipeline. If Logstash or Elasticsearch goes down, Filebeat queues events and retries. Your application keeps running without blocking on log delivery. Filebeat also uses ~10–30 MB RAM versus Logstash’s 500 MB+, making it ideal for application servers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3. Can I skip Logstash and send Filebeat directly to Elasticsearch?&lt;/strong&gt; &lt;br&gt;
Yes. Set output.elasticsearch instead of output.logstash in Filebeat. However, you lose the ability to parse and transform logs with grok filters. For simple use cases (no parsing needed), direct shipping is fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4. Why daily indices (boardgame-logs-2026.03.11) instead of a single index?&lt;/strong&gt; &lt;br&gt;
Daily indices enable simple retention management (delete indices older than N days), improve search performance (Elasticsearch skips irrelevant time ranges), and make index management operations (backup, restore) more granular.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5. How much disk space does the ELK stack need?&lt;/strong&gt; &lt;br&gt;
Rough estimate: 1 GB of raw logs produces ~1.5–2 GB of Elasticsearch data (due to indexing overhead). For 100 MB/day of logs with 30-day retention, budget ~6 GB for Elasticsearch data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q6. Why must multiline.pattern use single quotes in YAML?&lt;/strong&gt; &lt;br&gt;
YAML interprets backslash sequences in double-quoted strings (\d becomes an invalid escape). Single quotes treat the content literally, preserving the regex pattern for Filebeat.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q7. How do I add more application servers?&lt;/strong&gt; &lt;br&gt;
Install Filebeat on each server, point it to the same Logstash endpoint. Add a fields section to distinguish servers:&lt;br&gt;
filebeat.inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;type: log
enabled: true
paths:

&lt;ul&gt;
&lt;li&gt;/var/log/myapp/*.log
fields:
server_name: web-02
environment: production&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Q8. Is this setup production-ready as described?&lt;/strong&gt; &lt;br&gt;
For internal use, yes. For public-facing production, enable Elasticsearch security (xpack.security.enabled: true), use TLS certificates for all inter-component communication, put Kibana behind a reverse proxy with authentication, and configure Index Lifecycle Management for automatic cleanup.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Centralized logging transforms debugging from “SSH into each server and grep” to “search once, find everywhere.”&lt;/li&gt;
&lt;li&gt;Filebeat belongs on the application server, not the ELK server. It is lightweight (~10–30 MB RAM) and handles backpressure gracefully.&lt;/li&gt;
&lt;li&gt;Logstash’s grok filter turns unstructured log lines into structured, searchable fields (timestamp, loglevel, logmessage).&lt;/li&gt;
&lt;li&gt;Protocol mismatch (https:// vs http://) between Kibana and Elasticsearch is the most common setup failure. Always match the protocol to Elasticsearch’s actual SSL configuration.&lt;/li&gt;
&lt;li&gt;YAML formatting causes most Filebeat config errors - use single quotes for regex, no duplicate keys, no leading spaces on top-level keys.&lt;/li&gt;
&lt;li&gt;Daily indices (boardgame-logs-%{+YYYY.MM.dd}) simplify retention management and improve query performance.&lt;/li&gt;
&lt;li&gt;Security is not optional in production - enable xpack.security, use TLS, and restrict port access via security groups.&lt;/li&gt;
&lt;li&gt;Test connectivity bottom-up: Elasticsearch first, then Logstash, then Kibana, then Filebeat.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Setting up the ELK stack is not just about installing four packages - it is about building a reliable data pipeline that turns scattered log files into searchable, visualizable insights. Each component has a clear role: Filebeat ships, Logstash transforms, Elasticsearch stores, and Kibana visualizes.&lt;/p&gt;

&lt;p&gt;The most common failures are not in the software itself, but in the configuration glue between components: protocol mismatches between Kibana and Elasticsearch, YAML formatting errors in Filebeat, unopened firewall ports between servers, and missing runtime dependencies.&lt;/p&gt;

&lt;p&gt;By following the step-by-step approach in this guide - installing bottom-up (Elasticsearch → Logstash → Kibana → Filebeat), verifying each component before moving to the next, and understanding why each configuration setting exists - you can set up a production-grade centralized logging system that scales from a single application to dozens of services.&lt;/p&gt;

&lt;p&gt;Once the pipeline is flowing, the real value begins: building dashboards for error rates, setting up alerts for anomalies, and turning your logs from an afterthought into your first line of defense.&lt;/p&gt;

&lt;p&gt;About the Author:&lt;em&gt;Rajan is a DevOps Engineer at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;, specializing in automation infrastructure, Optimize the CI/CD Pipelines and ensuring seamless deployments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>elk</category>
      <category>elasticsearch</category>
      <category>logstash</category>
      <category>kibana</category>
    </item>
    <item>
      <title>Nginx + PHP + MySQL Optimisations and Parameter Calculations</title>
      <dc:creator>Narendra Chauhan</dc:creator>
      <pubDate>Fri, 03 Apr 2026 06:38:00 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/nginx-php-mysql-optimisations-and-parameter-calculations-3min</link>
      <guid>https://dev.to/addwebsolutionpvtltd/nginx-php-mysql-optimisations-and-parameter-calculations-3min</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Premature optimization is the root of all evil but lack of optimisation is the root of outages.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Architecture Overview&lt;/li&gt;
&lt;li&gt;Why Optimisation Is Required&lt;/li&gt;
&lt;li&gt;Nginx Optimisations &amp;amp; Parameter Calculations&lt;/li&gt;
&lt;li&gt;PHP-FPM Optimisations &amp;amp; Parameter Calculations&lt;/li&gt;
&lt;li&gt;MySQL Optimisations &amp;amp; Parameter Calculations&lt;/li&gt;
&lt;li&gt;System-Level Optimisations (Linux)&lt;/li&gt;
&lt;li&gt;Practical Example: Small vs Medium vs Large Server&lt;/li&gt;
&lt;li&gt;Interesting Facts &amp;amp; Statistics&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Key Takeaways&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;Modern web applications rely heavily on the Nginx + PHP + MySQL (LEMP) stack. While default configurations work for testing, they are not suitable for production traffic.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Faster page load time&lt;/li&gt;
&lt;li&gt;Better concurrency handling&lt;/li&gt;
&lt;li&gt;Lower memory and CPU usage&lt;/li&gt;
&lt;li&gt;Higher stability under load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This document explains what to optimise, why to optimise, and how to calculate parameters practically.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Architecture Overview
&lt;/h2&gt;

&lt;p&gt;A typical request flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client sends HTTP request&lt;/li&gt;
&lt;li&gt;Nginx handles connection &amp;amp; static content&lt;/li&gt;
&lt;li&gt;PHP-FPM processes dynamic PHP requests&lt;/li&gt;
&lt;li&gt;MySQL serves data from database&lt;/li&gt;
&lt;li&gt;Response sent back to client&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each layer must be tuned together, not individually.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Why Optimisation Is Required
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Default settings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are conservative&lt;/li&gt;
&lt;li&gt;Waste available RAM&lt;/li&gt;
&lt;li&gt;Limit concurrency&lt;/li&gt;
&lt;li&gt;Cause slow response under load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common Problems Without Optimisation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;502 / 504 Gateway errors&lt;/li&gt;
&lt;li&gt;High CPU load&lt;/li&gt;
&lt;li&gt;PHP-FPM “server reached max_children”&lt;/li&gt;
&lt;li&gt;MySQL “Too many connections”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Nginx Optimisations &amp;amp; Parameter Calculations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Key Nginx Parameters&lt;/strong&gt;&lt;br&gt;
worker_processes auto;&lt;br&gt;
worker_connections 4096;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is worker_processes&lt;/strong&gt;&lt;br&gt;
Number of worker processes&lt;br&gt;
Best practice: match CPU cores&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nproc&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
4 CPU cores → worker_processes 4;&lt;br&gt;
What is worker_connections&lt;br&gt;
Maximum connections per worker&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Total Max Connections&lt;/strong&gt;&lt;br&gt;
worker_processes × worker_connections&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;4 × 4096 = 16,384 concurrent connections&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended Extra Optimisations&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use epoll;
multi_accept on;

sendfile on;
tcp_nopush on;
tcp_nodelay on;

keepalive_timeout 65;
keepalive_requests 1000;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. PHP-FPM Optimisations &amp;amp; Parameter Calculations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Key PHP-FPM Settings&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How to Calculate pm.max_children&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find average PHP process memory:
ps -ylC php-fpm --sort:rss&lt;/li&gt;
&lt;li&gt;Formula:
Available RAM for PHP / Avg PHP process size&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Available RAM: 2 GB&lt;/li&gt;
&lt;li&gt;Avg PHP process: 100 MB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2048 / 100 ≈ 20&lt;br&gt;
pm.max_children = 20&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other Important PHP Optimisations&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request_terminate_timeout = 60
max_execution_time = 60
memory_limit = 256M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Enable OPcache&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. MySQL Optimisations &amp;amp; Parameter Calculations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Key MySQL Parameters&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 2
max_connections = 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How to Calculate innodb_buffer_pool_size&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allocate 60–70% of total RAM (dedicated DB server)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server RAM: 4 GB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4 × 70% ≈ 2.8 GB&lt;br&gt;
Use 2G or 3G&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connection Calculation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional Recommended Settings&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query_cache_type = 0
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. System-Level Optimisations (Linux)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;File Descriptors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ulimit -n 100000&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kernel Tuning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;net.core.somaxconn = 65535&lt;br&gt;
net.ipv4.tcp_max_syn_backlog = 65535&lt;br&gt;
vm.swappiness = 10&lt;/p&gt;
&lt;h2&gt;
  
  
  8. Practical Server Size Examples
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Small Server (2 CPU / 2 GB RAM)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nginx workers: 2&lt;/li&gt;
&lt;li&gt;worker_connections: 2048&lt;/li&gt;
&lt;li&gt;PHP max_children: 10&lt;/li&gt;
&lt;li&gt;MySQL buffer pool: 1G&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Medium Server (4 CPU / 8 GB RAM)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nginx workers: 4&lt;/li&gt;
&lt;li&gt;worker_connections: 4096&lt;/li&gt;
&lt;li&gt;PHP max_children: 30–40&lt;/li&gt;
&lt;li&gt;MySQL buffer pool: 4–5G&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Large Server (8 CPU / 16 GB RAM)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nginx workers: 8&lt;/li&gt;
&lt;li&gt;worker_connections: 8192&lt;/li&gt;
&lt;li&gt;PHP max_children: 60–80&lt;/li&gt;
&lt;li&gt;MySQL buffer pool: 10–12G&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Practical Demonstration (Images Explained)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1. NGINX OPTIMISATION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameter Calculations&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Step 1.1  Backup current nginx.conf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1.2  Check current config&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  cat /etc/nginx/nginx.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Screenshot: Current state before changes&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%2F8ulx50hm6zu2uul76f91.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%2F8ulx50hm6zu2uul76f91.png" alt=" " width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1.3  Edit nginx.conf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/nginx/nginx.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Replace/update with this optimized config:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user www-data;
  worker_processes 2;                    # = nproc (2 cores)
  worker_rlimit_nofile 65535;
  pid /run/nginx.pid;
  include /etc/nginx/modules-enabled/*.conf;

  events {
      worker_connections 1024;           # 2 x 1024 = 2048 total connections
      use epoll;                         # Linux best event model
      multi_accept on;                   # Accept multiple connections at once
  }

  http {

      # Basic Settings
      sendfile on;
      tcp_nopush on;
      tcp_nodelay on;
      keepalive_timeout 30;              # Reduced from default 75s
      keepalive_requests 100;
      types_hash_max_size 2048;
      server_tokens off;                 # Hide nginx version

      client_max_body_size 20m;
      client_body_buffer_size 128k;
      client_header_buffer_size 1k;
      large_client_header_buffers 4 8k;
      client_body_timeout 12;
      client_header_timeout 12;
      send_timeout 10;

      include /etc/nginx/mime.types;
      default_type application/octet-stream;

      # Logging Settings
      access_log /var/log/nginx/access.log;
      error_log /var/log/nginx/error.log warn;   # Only warn+ to reduce I/O

      # Gzip Settings
      gzip on;
      gzip_vary on;
      gzip_proxied any;
      gzip_comp_level 3;                 # Level 3 = good ratio, low CPU
      gzip_min_length 1024;              # Don't compress tiny files
      gzip_buffers 16 8k;
      gzip_http_version 1.1;
      gzip_types
          text/plain
          text/css
          text/javascript
          application/javascript
          application/json
          application/xml
          image/svg+xml
          font/woff2;


      # Open File Cache
      open_file_cache max=1000 inactive=20s;
      open_file_cache_valid 30s;
      open_file_cache_min_uses 2;
      open_file_cache_errors on;

      # FastCGI Cache (optional - enable per site)
      fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=PHPCACHE:10m
                         max_size=100m inactive=60m use_temp_path=off;

      include /etc/nginx/conf.d/*.conf;
      include /etc/nginx/sites-enabled/*;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1.4  Create FastCGI cache directory&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; sudo mkdir -p /var/cache/nginx
  sudo chown www-data:www-data /var/cache/nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1.5  Test and reload Nginx&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nginx -t
  sudo systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Screenshot: nginx -t showing syntax is ok and test is successful&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%2F9z8ztz2au7j9h1wf5s6n.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%2F9z8ztz2au7j9h1wf5s6n.png" alt=" " width="800" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1.6  Verify Nginx is running with new settings&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nginx -T | grep -E "worker_processes|worker_connections|gzip|keepalive_timeout"
systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Screenshot: Running status + key parameters&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%2Fhf2by2wlnnfzaj9mau0a.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%2Fhf2by2wlnnfzaj9mau0a.png" alt=" " width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2. PHP-FPM OPTIMISATION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameter Calculations&lt;/strong&gt;&lt;br&gt;
Available RAM for PHP-FPM: ~150MB (conservative, leaving room for MySQL + Nginx)&lt;br&gt;
  Average PHP-FPM process size: ~30-40MB&lt;br&gt;
  Formula: pm.max_children = 150 / 35 ≈ 4&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PHP-FPM Parameters Calculation&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;pm&lt;/strong&gt;&lt;br&gt;
 Formula: Dynamic (best for variable traffic)&lt;br&gt;
 Value: dynamic&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pm.max_children&lt;/strong&gt;&lt;br&gt;
 Formula: 150MB ÷ 35MB/process&lt;br&gt;
 Value: 4&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pm.start_servers&lt;/strong&gt;&lt;br&gt;
 Formula: pm.max_children / 2&lt;br&gt;
 Value: 2&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pm.min_spare_servers&lt;/strong&gt;&lt;br&gt;
 Formula: pm.start_servers / 2&lt;br&gt;
 Value: 1&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pm.max_spare_servers&lt;/strong&gt;&lt;br&gt;
 Formula: pm.start_servers&lt;br&gt;
 Value: 2&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pm.max_requests&lt;/strong&gt;&lt;br&gt;
 Formula: Prevent memory leaks&lt;br&gt;
 Value: 500&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2.1  Check PHP-FPM version path&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  php -v
  ls /etc/php/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2.2  Backup pool config&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo cp/etc/php/8.4/fpm/pool.d/www.conf/etc /php/8.4/fpm/pool.d/www.conf.bak
sudo cp /etc/php/8.4/fpm/php.ini /etc/php/8.4/fpm/php.ini.bak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2.3  Check current PHP process memory usage&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run this to see actual PHP-FPM process sizes
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ps aux | grep php-fpm | grep -v grep | awk '{sum += $6} END {print "Total RSS:", sum/1024, "MB"; print "Count:", NR; print "Avg per process:", sum/NR/1024, "MB"}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Screenshot:&lt;/strong&gt; Current process sizes.&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%2F54on5le82nhiwpw62eyt.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%2F54on5le82nhiwpw62eyt.png" alt=" " width="800" height="70"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2.4  Edit PHP-FPM pool config&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/php/8.4/fpm/pool.d/www.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Find and update these values (search with Ctrl+W in nano):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[www]
user = www-data
group = www-data

listen = /run/php/php8.4-fpm.sock
listen.owner = www-data
listen.group = www-data

pm = dynamic
pm.max_children = 4
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 2
pm.max_requests = 500     ;Restart workers after 500 requests (prevents memory leaks)
pm.process_idle_timeout = 10s

pm.status_path = /status  ; Enable FPM status page
ping.path = /ping

slowlog = /var/log/php8.4-fpm-slow.log
request_slowlog_timeout = 5s     ; Log requests taking &amp;gt; 5 seconds
security.limit_extensions = .php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2.5  Tune PHP OPcache&lt;/strong&gt;&lt;br&gt;
  &lt;strong&gt;sudo nano /etc/php/8.4/mods-available/opcache.ini&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zend_extension=opcache

  ; Enable OPcache
  opcache.enable=1
  opcache.enable_cli=0

  ; Memory: 64MB for low-RAM server
  opcache.memory_consumption=64
  opcache.interned_strings_buffer=8
  opcache.max_accelerated_files=10000

  ; Production settings (set validate_timestamps=0 in prod)
  opcache.validate_timestamps=1
  opcache.revalidate_freq=60

  opcache.save_comments=1
  opcache.max_wasted_percentage=10
  opcache.use_cwd=1

  ; JIT (PHP 8.x feature)
  opcache.jit_buffer_size=32M
  opcache.jit=1255
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2.6  Tune PHP.ini key values&lt;/strong&gt;&lt;br&gt;
  &lt;strong&gt;sudo nano /etc/php/8.4/fpm/php.ini&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find and update:
  ; Memory limit per PHP process
  memory_limit = 128M

  ; Upload/POST limits
  upload_max_filesize = 20M
  post_max_size = 25M
  max_execution_time = 60
  max_input_time = 60

  ; Error handling (production)
  display_errors = Off
  log_errors = On
  error_log = /var/log/php_errors.log

  ; Session handling
  session.gc_maxlifetime = 1440
  session.cookie_httponly = 1
  session.cookie_secure = 1

  ; Disable dangerous functions
  disable_functions = exec,passthru,shell_exec,system,proc_open,popen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2.7  Restart PHP-FPM and verify&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo php-fpm8.4 -t
  sudo systemctl restart php8.4-fpm
  sudo systemctl status php8.4-fpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Screenshot: PHP-FPM status showing active (running)&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%2F7qt80y78sp1pvjj0uc6q.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%2F7qt80y78sp1pvjj0uc6q.png" alt=" " width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2.8  Verify OPcache is active&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php -r "var_dump(opcache_get_status());" | head -30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- or check via CLI&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php -i | grep -E "opcache|OPcache"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Screenshot: OPcache enabled status&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%2F3xbp914o9gh6ucb37o0s.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%2F3xbp914o9gh6ucb37o0s.png" alt=" " width="800" height="727"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2.9  Check PHP-FPM processes after restart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ps aux | grep php-fpm | grep -v grep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- Should show master + 2 worker processes (pm.start_servers=2)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Screenshot:&lt;/strong&gt; FPM process list&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%2F5bpg2ffx4sviu3jjhciz.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%2F5bpg2ffx4sviu3jjhciz.png" alt=" " width="800" height="58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3.  MYSQL OPTIMISATION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameter Calculations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RAM budget for MySQL: ~200MB (out of 914MB total)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;innodb_buffer_pool_size&lt;/strong&gt;&lt;br&gt;
Formula: ~20% of RAM (shared server)&lt;br&gt;
Value: 192M&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;innodb_buffer_pool_instances&lt;/strong&gt;&lt;br&gt;
Formula: buffer_pool ÷ 128M&lt;br&gt;
Value: 1&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;max_connections&lt;/strong&gt;&lt;br&gt;
Formula: Low RAM = conservative&lt;br&gt;
Value: 50&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;innodb_log_file_size&lt;/strong&gt;&lt;br&gt;
Formula: 25% of buffer pool&lt;br&gt;
Value: 48M&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tmp_table_size&lt;/strong&gt;&lt;br&gt;
Formula: Memory temporary tables&lt;br&gt;
Value: 16M&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;max_heap_table_size&lt;/strong&gt;&lt;br&gt;
 Formula: Same as tmp_table_size&lt;br&gt;
 Value: 16M&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;thread_cache_size&lt;/strong&gt;&lt;br&gt;
 Formula: Reuse threads&lt;br&gt;
 Value: 8&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;table_open_cache&lt;/strong&gt;&lt;br&gt;
 Formula: Open tables cache&lt;br&gt;
 Value: 400&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3.1  Check current MySQL config and status&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo cp /etc/mysql/mysql.conf.d/mysqld.cnf /etc/mysql/mysql.conf.d/mysqld.cnf.bak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- Check current variables&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool%';"
  mysql -u root -p -e "SHOW VARIABLES LIKE 'max_connections';"
  mysql -u root -p -e "SHOW STATUS LIKE 'Threads_connected';"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Screenshot:&lt;/strong&gt; Current MySQL variables&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%2Fmox0cz0iyp8k74nux7u3.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%2Fmox0cz0iyp8k74nux7u3.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3.2  Check actual MySQL memory usage&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql -u root -p -e "
  SELECT
    ROUND(@@innodb_buffer_pool_size/1024/1024, 0) AS 'Buffer Pool MB',
    ROUND(@@key_buffer_size/1024/1024, 0) AS 'Key Buffer MB',
    @@max_connections AS 'Max Connections',
    @@thread_stack/1024 AS 'Thread Stack KB';
  "
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Screenshot:&lt;/strong&gt; Current MySQL memory config&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%2F3l1e1yqi9eaht5w3qpx8.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%2F3l1e1yqi9eaht5w3qpx8.png" alt=" " width="758" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3.3  Edit MySQL config&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add/update under [mysqld]:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[mysqld]
  pid-file        = /var/run/mysqld/mysqld.pid
  socket          = /var/run/mysqld/mysqld.sock
  datadir         = /var/lib/mysql
  log-error       = /var/log/mysql/error.log

  #
  # ===== MEMORY SETTINGS =====
  # Server has 914MB RAM - allocate ~200MB for MySQL
  #
  innodb_buffer_pool_size         = 192M    # Main InnoDB cache (most important!)
  innodb_buffer_pool_instances    = 1       # 1 instance (&amp;lt; 1GB pool)
  innodb_log_file_size            = 48M     # ~25% of buffer pool
  innodb_log_buffer_size          = 8M
  innodb_flush_log_at_trx_commit  = 2       # Slight risk, big perf gain (use 1 for strict ACID)

  #
  # ===== CONNECTION SETTINGS =====
  #
  max_connections         = 50             # Low RAM = keep connections limited
  thread_cache_size       = 8             # Reuse threads, avoid creation overhead
  wait_timeout            = 120           # Kill idle connections after 2 min
  interactive_timeout     = 120

  #
  # ===== QUERY CACHE (removed in MySQL 8.0, skip) =====
  # MySQL 8.0 removed query_cache - use ProxySQL or app-level cache

  #
  # ===== TABLE CACHE =====
  #
  table_open_cache        = 400
  table_definition_cache  = 400

  #
  # ===== TEMP TABLES =====
  #
  tmp_table_size          = 16M
  max_heap_table_size     = 16M

  #
  # ===== InnoDB I/O =====
  #
  innodb_file_per_table           = 1
  innodb_flush_method             = O_DIRECT  # Avoid double buffering with OS cache
  innodb_read_io_threads          = 2         # = CPU cores
  innodb_write_io_threads         = 2         # = CPU cores

  #
  # ===== SLOW QUERY LOG =====
  #
  slow_query_log          = 1
  slow_query_log_file     = /var/log/mysql/slow.log
  long_query_time         = 2             # Log queries &amp;gt; 2 seconds
  log_queries_not_using_indexes = 1

  #
  # ===== BINARY LOG (disable if not using replication) =====
  #
  # skip-log-bin                           # Uncomment if no replication needed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3.4  Validate and restart MySQL&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mysqld --validate-config
  sudo systemctl restart mysql
  sudo systemctl status mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Screenshot:&lt;/strong&gt; MySQL status active&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%2Fi7v681msbropem0xbz3a.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%2Fi7v681msbropem0xbz3a.png" alt=" " width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3.5  Verify new MySQL variables&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql -u root -p -e "
  SELECT 'innodb_buffer_pool_size' AS Variable,
         ROUND(@@innodb_buffer_pool_size/1024/1024,0) AS 'Value (MB)'
  UNION SELECT 'max_connections', @@max_connections
  UNION SELECT 'innodb_log_file_size MB', ROUND(@@innodb_log_file_size/1024/1024,0)
  UNION SELECT 'tmp_table_size MB', ROUND(@@tmp_table_size/1024/1024,0)
  UNION SELECT 'thread_cache_size', @@thread_cache_size;
  "
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Screenshot:&lt;/strong&gt; New values confirmed&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%2Fux8rtbud97okrc2amssb.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%2Fux8rtbud97okrc2amssb.png" alt=" " width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3.6  Check MySQL memory usage post-restart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  free -h
  ps aux | sort -k6 -rn | head -10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Screenshot:&lt;/strong&gt; Overall memory after all services tuned&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%2F1fxt48wa7i5j3vmc5bfg.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%2F1fxt48wa7i5j3vmc5bfg.png" alt=" " width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Measure first, tune second, and monitor always.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 4. FINAL VERIFICATION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4.1  Check all services running&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  systemctl status nginx php8.4-fpm mysql --no-pager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4.2  Full memory picture&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;free -h
  ps aux --sort=-%mem | head -15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4.3  Check nginx + PHP working together&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Test nginx config is still valid
  sudo nginx -t

 Test PHP-FPM socket exists
  ls -la /run/php/php8.4-fpm.sock

 Check FPM status (if you added status page to your site config)
  curl http://localhost/status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4.4  Check MySQL slow log is active&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql -u root -p -e "SHOW VARIABLES LIKE 'slow_query%';"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4.5  Final health summary&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "=== NGINX ===" &amp;amp;&amp;amp; nginx -v &amp;amp;&amp;amp; systemctl is-active nginx
  echo "=== PHP-FPM ===" &amp;amp;&amp;amp; php -v | head -1 &amp;amp;&amp;amp; systemctl is-active php8.4-fpm
  echo "=== MYSQL ===" &amp;amp;&amp;amp; mysql --version &amp;amp;&amp;amp; systemctl is-active mysql
  echo "=== MEMORY ===" &amp;amp;&amp;amp; free -h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Screenshot:&lt;/strong&gt; Final health check&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%2Fsrpebst3v962c3sz682m.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%2Fsrpebst3v962c3sz682m.png" alt=" " width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your server is fully optimised. All phases verified:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phase 0  Swap 2GB active&lt;/li&gt;
&lt;li&gt;  Phase 1  Nginx tuned&lt;/li&gt;
&lt;li&gt;  Phase 2  PHP-FPM + OPcache + JIT enabled&lt;/li&gt;
&lt;li&gt;  Phase 3  MySQL InnoDB / connections / slow query log active&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. Interesting Facts &amp;amp; Statistics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1 second delay can reduce conversions by 7%&lt;/li&gt;
&lt;li&gt;OPcache can improve PHP performance by 2–3×&lt;/li&gt;
&lt;li&gt;MySQL buffer pool cache hit ratio above 99% is ideal&lt;/li&gt;
&lt;li&gt;Nginx handles 10× more concurrent connections than traditional servers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  11. FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1. Should I optimise Nginx, PHP, or MySQL first?&lt;/strong&gt;&lt;br&gt;
Start with PHP-FPM and MySQL, then tune Nginx.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2. Can wrong tuning crash the server?&lt;/strong&gt;&lt;br&gt;
Yes. Over-allocating RAM causes OOM kills.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3. Are these values fixed forever?&lt;/strong&gt;&lt;br&gt;
No. Recalculate after traffic growth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4. Do I need load testing?&lt;/strong&gt;&lt;br&gt;
Yes. Use tools like ab, wrk, or k6.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Optimisation is calculation-based, not guesswork&lt;/li&gt;
&lt;li&gt;PHP-FPM memory calculation is critical&lt;/li&gt;
&lt;li&gt;MySQL buffer pool has the biggest performance impact&lt;/li&gt;
&lt;li&gt;Nginx handles concurrency, not application logic&lt;/li&gt;
&lt;li&gt;Monitoring is mandatory after tuning&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Optimising Nginx + PHP + MySQL is not about copying configs from the internet—it is about understanding server resources, calculating limits, and balancing load across layers.&lt;br&gt;
&lt;strong&gt;A well-optimised stack:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handles higher traffic&lt;/li&gt;
&lt;li&gt;Reduces downtime&lt;/li&gt;
&lt;li&gt;Improves user experience&lt;/li&gt;
&lt;li&gt;Saves infrastructure cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About the Author:&lt;em&gt;Narendra is a DevOps Engineer at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;, specializing in automating infrastructure to improve efficiency and reliability.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>serveroptimization</category>
      <category>lempstack</category>
      <category>webperf</category>
      <category>nginxphpmysql</category>
    </item>
    <item>
      <title>Testing Node.js APIs: Jest, Supertest, and Best Practices</title>
      <dc:creator>Zemichael Mehretu</dc:creator>
      <pubDate>Tue, 31 Mar 2026 10:21:20 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/testing-nodejs-apis-jest-supertest-and-best-practices-3ddp</link>
      <guid>https://dev.to/addwebsolutionpvtltd/testing-nodejs-apis-jest-supertest-and-best-practices-3ddp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Fast tests are a productivity feature; reliable tests are a business feature.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reliable API tests are less about tool choice and more about test boundaries, data control, and deterministic execution.&lt;/li&gt;
&lt;li&gt;Jest + Supertest remains a practical default stack for HTTP API testing across Express, Fastify, and Nest-based services.&lt;/li&gt;
&lt;li&gt;The biggest gains come from balancing fast unit tests with focused integration and contract tests.&lt;/li&gt;
&lt;li&gt;Flaky tests usually indicate architecture or environment issues, not just “test instability.”&lt;/li&gt;
&lt;li&gt;A staged migration strategy outperforms rewriting the entire test suite at once.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Why Node.js API Test Suites Become Fragile Over Time&lt;/li&gt;
&lt;li&gt;Testing APIs in Practical Terms&lt;/li&gt;
&lt;li&gt;Core Testing Principles (The Guardrails)&lt;/li&gt;
&lt;li&gt;The Four Testing Layers for Node.js APIs&lt;/li&gt;
&lt;li&gt;Implementation Strategy for Engineering Teams&lt;/li&gt;
&lt;li&gt;Minimal Example: Create User Endpoint with Jest + Supertest&lt;/li&gt;
&lt;li&gt;Databases, Queues, and External Integrations&lt;/li&gt;
&lt;li&gt;Testing Strategy by Risk and Feedback Speed&lt;/li&gt;
&lt;li&gt;Migration Roadmap for Existing Node.js APIs&lt;/li&gt;
&lt;li&gt;Common Mistakes and How to Avoid Themdevf nf.f/fk&lt;/li&gt;
&lt;li&gt;When to Go Deep (and When to Keep It Lean)&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;li&gt;Interesting facts&lt;/li&gt;
&lt;li&gt;Stats&lt;/li&gt;
&lt;li&gt;Conclution&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1) Introduction
&lt;/h2&gt;

&lt;p&gt;Most Node.js teams start with a handful of endpoint tests and feel productive quickly. The challenge appears later: as endpoints multiply, integrations grow, and multiple teams contribute, test suites get slower, noisier, and harder to trust.&lt;/p&gt;

&lt;p&gt;At that point, the question changes from “Do we have tests?” to “Can we safely change behavior without fear?”&lt;/p&gt;

&lt;p&gt;Jest and Supertest are still a strong pair for this problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jest provides a mature runner, mocking, snapshots (when used carefully), parallelism controls, and strong TypeScript support.&lt;/li&gt;
&lt;li&gt;Supertest makes HTTP assertions straightforward by testing your app server boundary with minimal setup.
This guide focuses on practical, production-grade API testing: clear test architecture, reliable CI execution, and patterns that hold up as systems grow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2) Why Node.js API Test Suites Become Fragile Over Time
&lt;/h2&gt;

&lt;p&gt;Most API testing pain comes from boundary confusion, not from JavaScript itself.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Endpoint tests that also validate unrelated business rules, persistence details, and third-party behavior in one place.&lt;/li&gt;
&lt;li&gt;Excessive mocks that make tests pass while production behavior fails.&lt;/li&gt;
&lt;li&gt;Slow suites due to global setup, shared mutable state, or non-isolated databases.&lt;/li&gt;
&lt;li&gt;Flaky tests caused by timing assumptions, network dependency, or race conditions.&lt;/li&gt;
&lt;li&gt;Hard-to-debug failures because assertions are too broad (“status should be 200”) and not intent-focused.
As these issues accumulate, teams lose confidence. Developers re-run tests repeatedly, CI cycles grow, and delivery speed drops.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3) Testing APIs in Practical Terms
&lt;/h2&gt;

&lt;p&gt;Effective API testing separates policy from transport detail.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Policy: validation rules, authorization decisions, business invariants, idempotency behavior.&lt;/li&gt;
&lt;li&gt;Detail: HTTP framework wiring, DB driver specifics, queue providers, external SDK mechanics.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Test business behavior close to the domain/service layer where feedback is fast.&lt;/li&gt;
&lt;li&gt;Test HTTP contracts at the API boundary (status codes, schema shape, headers).&lt;/li&gt;
&lt;li&gt;Test integration seams (database, message broker, external APIs) explicitly and intentionally.&lt;/li&gt;
&lt;li&gt;Keep each test focused on one intent so failures explain what broke.
A useful test heuristic: if your storage engine changes, most behavioral tests should remain valid.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4) Core Testing Principles (The Guardrails)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Principle 1: Test Behavior, Not Implementation&lt;/strong&gt;&lt;br&gt;
Prefer assertions on outcomes (response payload, side effects, emitted events) over internal call counts unless interaction itself is the behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle 2: Keep Tests Deterministic&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Control time, randomness, and external I/O. Non-determinism is the fastest path to flaky pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle 3: Isolate by Layer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use unit tests for logic branches, integration tests for boundaries, and endpoint tests for HTTP contract confidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle 4: Keep Test Data Intentional&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use builders/factories with explicit defaults. Hidden fixture coupling creates accidental test dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle 5: Make Failures Actionable&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every failure should quickly answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What business behavior regressed?&lt;/li&gt;
&lt;li&gt;Which boundary failed?&lt;/li&gt;
&lt;li&gt;Is this deterministic or flaky?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Principle 6: Optimize for Feedback Loop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developers need fast local tests and reliable CI gates. Prioritize speed for high-frequency paths.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Contract tests protect teams from integration surprises better than shared assumptions.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  5) The Four Testing Layers for Node.js APIs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A) Unit Tests (Core Behavior)&lt;/strong&gt;&lt;br&gt;
Purpose: verify pure or near-pure logic quickly.&lt;br&gt;
Test here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validation utilities&lt;/li&gt;
&lt;li&gt;Domain services&lt;/li&gt;
&lt;li&gt;Policy evaluators (authz/eligibility)&lt;/li&gt;
&lt;li&gt;Data transformation helpers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No network I/O&lt;/li&gt;
&lt;li&gt;Minimal mocking&lt;/li&gt;
&lt;li&gt;Millisecond-level runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;B) Service/Use-Case Tests (Application Behavior)&lt;/strong&gt;&lt;br&gt;
Purpose: validate business workflows with mocked boundaries.&lt;br&gt;
Test here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use-case orchestration&lt;/li&gt;
&lt;li&gt;Branching by role/plan/state&lt;/li&gt;
&lt;li&gt;Error mapping from domain to application outcomes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mock repository/gateway interfaces&lt;/li&gt;
&lt;li&gt;Clear input-output assertions&lt;/li&gt;
&lt;li&gt;Strong signal for business regressions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;C) API Integration Tests (HTTP Boundary)&lt;/strong&gt;&lt;br&gt;
Purpose: verify endpoint contracts through real routing/middleware.&lt;br&gt;
Test here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Status and payload schema&lt;/li&gt;
&lt;li&gt;Auth middleware effects&lt;/li&gt;
&lt;li&gt;Validation and error format&lt;/li&gt;
&lt;li&gt;Idempotency and headers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run through supertest(app)&lt;/li&gt;
&lt;li&gt;Use real request pipeline&lt;/li&gt;
&lt;li&gt;Keep counts limited to meaningful scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;D) Infrastructure Integration Tests (Real Dependencies)&lt;/strong&gt;&lt;br&gt;
Purpose: validate adapter correctness with real systems.&lt;br&gt;
Test here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository against real DB (often containerized)&lt;/li&gt;
&lt;li&gt;Outbound gateway behavior against sandbox/stub&lt;/li&gt;
&lt;li&gt;Queue publish/consume adapter correctness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slower and fewer&lt;/li&gt;
&lt;li&gt;High confidence at critical seams&lt;/li&gt;
&lt;li&gt;Isolated environments required&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  6) Implementation Strategy for Engineering Teams
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Strategy 1: Start with High-Risk Endpoints&lt;/strong&gt;&lt;br&gt;
Prioritize money movement, authentication, billing, entitlement, and state-transition APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strategy 2: Define a Test Matrix per Endpoint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For each endpoint, define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;happy path,&lt;/li&gt;
&lt;li&gt;validation failures,&lt;/li&gt;
&lt;li&gt;authorization failures,&lt;/li&gt;
&lt;li&gt;business rule failures,&lt;/li&gt;
&lt;li&gt;idempotency/concurrency behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Strategy 3: Standardize Test Utilities&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create shared helpers for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app bootstrap,&lt;/li&gt;
&lt;li&gt;authenticated request context,&lt;/li&gt;
&lt;li&gt;test data factories,&lt;/li&gt;
&lt;li&gt;DB reset/seed.&lt;/li&gt;
&lt;li&gt;This reduces duplicated setup and inconsistent patterns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Strategy 4: Separate Fast vs Slow Pipelines&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run fast tests on every push; run heavier integration suites on merge or scheduled jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strategy 5: Enforce Test Ownership in Reviews&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Review checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the behavior covered at the right layer?&lt;/li&gt;
&lt;li&gt;Are assertions business-meaningful?&lt;/li&gt;
&lt;li&gt;Is the test deterministic?&lt;/li&gt;
&lt;li&gt;Does this duplicate lower-layer coverage?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Strategy 6: Track Quality Metrics&lt;/strong&gt;&lt;br&gt;
Monitor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;flaky test rate,&lt;/li&gt;
&lt;li&gt;mean CI duration,&lt;/li&gt;
&lt;li&gt;re-run frequency,&lt;/li&gt;
&lt;li&gt;escaped defect categories.
Good testing architecture should improve these over time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  7) Minimal Example: Create User Endpoint with Jest + Supertest
&lt;/h2&gt;

&lt;p&gt;The goal is clarity of boundaries, not framework-specific depth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/app.ts&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&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="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&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;email&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&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="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;422&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="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VALIDATION_ERROR&lt;/span&gt;&lt;span class="dl"&gt;'&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;email and name are required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="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;201&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;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;usr_123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;test/users.create.spec.ts&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;request&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;supertest&lt;/span&gt;&lt;span class="dl"&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;app&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;../src/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST /users&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;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;creates a user when payload is valid&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="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;response&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;request&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&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;send&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sam@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sam&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&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;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sam@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sam&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;returns 422 for invalid payload&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="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;response&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;request&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&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;send&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sam@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;code&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VALIDATION_ERROR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;package.json (relevant scripts)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --runInBand"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test:watch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test:ci"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --coverage --maxWorkers=50%"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In real systems, route handlers should delegate to use cases/services. Tests then become cleaner: unit tests cover rules, while Supertest verifies HTTP contract and middleware behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  8) Databases, Queues, and External Integrations
&lt;/h2&gt;

&lt;p&gt;These boundaries create most false confidence if not tested deliberately.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database: prefer isolated test DB instances, deterministic seeders, and teardown per test or per suite.&lt;/li&gt;
&lt;li&gt;Queues/events: test enqueue intent at service level, then test adapter correctness separately.&lt;/li&gt;
&lt;li&gt;External APIs: avoid live dependencies in regular CI; use stable stubs, contract checks, or sandbox environments.&lt;/li&gt;
&lt;li&gt;Retries/timeouts: assert observable outcomes (e.g., mapped errors, retry caps), not private implementation internals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A practical split:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;regular CI: no real internet dependency,&lt;/li&gt;
&lt;li&gt;nightly/extended pipeline: sandbox integration checks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9) Testing Strategy by Risk and Feedback Speed
&lt;/h2&gt;

&lt;p&gt;Treat tests as a portfolio.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fast lane (minutes): unit + selected service tests.&lt;/li&gt;
&lt;li&gt;Core lane (merge gate): API integration for critical endpoints.&lt;/li&gt;
&lt;li&gt;Extended lane (scheduled): infra/sandbox checks, broader resilience scenarios.
This balances confidence and developer velocity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Recommended safeguards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fail build on flaky test detection thresholds.&lt;/li&gt;
&lt;li&gt;Quarantine unstable tests with owner + fix-by date.&lt;/li&gt;
&lt;li&gt;Keep coverage goals directional, not vanity metrics.&lt;/li&gt;
&lt;li&gt;Prefer mutation testing selectively on high-value modules.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10) Migration Roadmap for Existing Node.js APIs
&lt;/h2&gt;

&lt;p&gt;Avoid all-at-once rewrites.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify top 5 risky endpoints by incident history or business criticality.&lt;/li&gt;
&lt;li&gt;Add baseline Supertest contract tests for current behavior.&lt;/li&gt;
&lt;li&gt;Extract business logic from route handlers into testable services/use cases.&lt;/li&gt;
&lt;li&gt;Add unit/service tests around extracted rules.&lt;/li&gt;
&lt;li&gt;Introduce integration tests for critical DB/external adapters.&lt;/li&gt;
&lt;li&gt;Reduce over-mocked endpoint tests and remove duplicate coverage.&lt;/li&gt;
&lt;li&gt;Enforce testing checklist in pull requests.&lt;/li&gt;
&lt;li&gt;Repeat by vertical slice.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This path allows continuous delivery while improving reliability incrementally.&lt;/p&gt;

&lt;h2&gt;
  
  
  11) Common Mistakes and How to Avoid Them
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Over-mocking everything: tests become fiction; keep meaningful boundaries real.&lt;/li&gt;
&lt;li&gt;Only endpoint tests: slow suites and weak failure localization.&lt;/li&gt;
&lt;li&gt;Shared mutable fixtures: hidden coupling and random failures.&lt;/li&gt;
&lt;li&gt;Ignoring time/state transitions: retries, TTLs, and async workflows go untested.&lt;/li&gt;
&lt;li&gt;Snapshot overuse: brittle assertions with low business signal.&lt;/li&gt;
&lt;li&gt;No ownership model: flaky tests linger and trust decays.
Fixes are process + architecture: test at the right layer, isolate state, and treat flaky tests as production bugs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12) When to Go Deep (and When to Keep It Lean)
&lt;/h2&gt;

&lt;p&gt;Go deeper when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs control payments, access, compliance, or irreversible workflows.&lt;/li&gt;
&lt;li&gt;multiple teams ship to the same service.&lt;/li&gt;
&lt;li&gt;incident cost is high and regressions are expensive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep it leaner when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;service is internal and low-risk,&lt;/li&gt;
&lt;li&gt;behavior is straightforward CRUD,&lt;/li&gt;
&lt;li&gt;change frequency and impact are low.&lt;/li&gt;
&lt;li&gt;Testing depth should match business risk, not trend pressure.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“A stable test suite is not a luxury in API teams; it is delivery infrastructure.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  13) FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is Jest still a good default for Node.js API testing?&lt;/strong&gt;&lt;br&gt;
Yes. It remains a practical default for most teams due to ecosystem maturity, tooling support, and straightforward CI integration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do we need Supertest if we already unit test services?&lt;/strong&gt;&lt;br&gt;
Yes, for HTTP contract confidence. Unit tests do not validate routing, middleware, serialization, and error envelope behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much mocking is too much?&lt;/strong&gt;&lt;br&gt;
If tests pass while real integration repeatedly fails, mocking is likely hiding boundary problems. Mock at external seams, not core behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should we test against real third-party APIs in CI?&lt;/strong&gt;&lt;br&gt;
Usually not in the main pipeline. Prefer deterministic stubs/contracts in regular CI and schedule sandbox verification separately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a healthy target for coverage?&lt;/strong&gt;&lt;br&gt;
There is no universal number. Prioritize meaningful coverage of critical flows and failure modes over headline percentages.&lt;/p&gt;

&lt;h2&gt;
  
  
  14) References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Jest Documentation: &lt;a href="https://jestjs.io" rel="noopener noreferrer"&gt;https://jestjs.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Supertest (GitHub): &lt;a href="https://github.com/ladjs/supertest" rel="noopener noreferrer"&gt;https://github.com/ladjs/supertest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Node.js Documentation (Testing &amp;amp; Runtime): &lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;https://nodejs.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Martin Fowler   Test Pyramid: &lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html" rel="noopener noreferrer"&gt;https://martinfowler.com/articles/practical-test-pyramid.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Google SRE Workbook (Testing in Production Concepts): &lt;a href="https://sre.google/workbook/" rel="noopener noreferrer"&gt;https://sre.google/workbook/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  15) Interesting Facts
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;JavaScript continues to be one of the most widely used languages globally, and Node.js remains one of the most commonly used web technologies among professional developers. Source: &lt;a href="https://survey.stackoverflow.co/2024/" rel="noopener noreferrer"&gt;https://survey.stackoverflow.co/2024/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Testing has become a first-class topic in modern JavaScript ecosystems, with dedicated community tracking for framework usage, satisfaction, and retention trends. Source: &lt;a href="https://stateofjs.com/" rel="noopener noreferrer"&gt;https://stateofjs.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Node.js now includes an official built-in test runner, which reflects how central testing has become in backend JavaScript workflows. Source: &lt;a href="https://nodejs.org/api/test.html" rel="noopener noreferrer"&gt;https://nodejs.org/api/test.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Jest provides native support for parallel execution and coverage reporting, which is why many teams keep it as a CI-friendly default for API and service testing. Source: &lt;a href="https://jestjs.io/docs/cli" rel="noopener noreferrer"&gt;https://jestjs.io/docs/cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Supertest is designed to test HTTP servers without opening a real network port, making endpoint tests faster and more deterministic in local and CI environments. Source: &lt;a href="https://github.com/ladjs/supertest" rel="noopener noreferrer"&gt;https://github.com/ladjs/supertest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Jest is an all-in-one testing solution that includes a test runner, assertion library, and mocking capabilities out of the box.&lt;/li&gt;
&lt;li&gt;Supertest can simulate HTTP requests directly against an Express app, making tests faster and more reliable.&lt;/li&gt;
&lt;li&gt;Jest runs tests in parallel by default, significantly improving execution speed for large test suites.&lt;/li&gt;
&lt;li&gt;API testing in Node.js often focuses more on integration tests rather than pure unit tests due to the nature of backend systems.&lt;/li&gt;
&lt;li&gt;Best practice emphasizes testing API behavior (status codes, responses) rather than internal implementation details.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  16) Stats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;According to the Stack Overflow Developer Survey, a majority of Node.js developers use automated testing in production environments.Source: &lt;a href="https://survey.stackoverflow.co/" rel="noopener noreferrer"&gt;https://survey.stackoverflow.co/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Jest has 40k+ stars on GitHub and millions of weekly npm downloads, making it one of the most widely used JavaScript testing frameworks.Source: &lt;a href="https://github.com/facebook/jest" rel="noopener noreferrer"&gt;https://github.com/facebook/jest&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Tools like Supertest are commonly used with Express.js for API testing due to their ability to test endpoints without starting a live server.Source: &lt;a href="https://github.com/visionmedia/supertest" rel="noopener noreferrer"&gt;https://github.com/visionmedia/supertest&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  17) Conclusion
&lt;/h2&gt;

&lt;p&gt;Testing Node.js APIs effectively is not about maximizing test count; it is about placing the right tests at the right boundaries. With Jest and Supertest, teams can build a fast, trustworthy feedback loop by combining deterministic unit/service tests, focused API contract tests, and intentional integration checks. Over time, this reduces incident risk, shortens debugging cycles, and makes API evolution safer.&lt;/p&gt;

&lt;p&gt;About the Author: &lt;em&gt;Zemichael is a fullstackDeveloper at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWeb Solution&lt;/a&gt;.Crafting web experiences with robust architecture, performance focus, and design thinking.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>jest</category>
      <category>supertest</category>
      <category>apitesting</category>
    </item>
    <item>
      <title>Common Mistakes Laravel Developers Make (And How to Avoid Them)</title>
      <dc:creator>Lakashya Upadhyay</dc:creator>
      <pubDate>Fri, 27 Mar 2026 08:23:53 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/common-mistakes-laravel-developers-make-and-how-to-avoid-them-3oem</link>
      <guid>https://dev.to/addwebsolutionpvtltd/common-mistakes-laravel-developers-make-and-how-to-avoid-them-3oem</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Controllers should coordinate, not decide.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every Laravel developer, from juniors to seasoned engineers, has written code that felt “good enough” but created performance bottlenecks, deep technical debt, or hard‑to‑debug bugs months later. Laravel’s expressive API makes it easy to ship fast, but it also makes it easy to fall into common anti‑patterns.&lt;/p&gt;

&lt;p&gt;This guide walks through the most frequent mistakes Laravel developers make in production, explains why they’re harmful, and shows how to refactor them into clean, maintainable structures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Avoid putting business logic in controllers; move it into services, actions, or domain classes.&lt;/li&gt;
&lt;li&gt;Use Eloquent relationships, eager loading, and proper indexing to prevent N+1 queries.&lt;/li&gt;
&lt;li&gt;Organize your code with proper folders, route groups, and naming conventions.&lt;/li&gt;
&lt;li&gt;Separate validation from controllers and reuse it via Form Requests or validation rules.&lt;/li&gt;
&lt;li&gt;Use migrations, tests, and documentation to keep your app scalable and on‑team‑friendly.&lt;/li&gt;
&lt;li&gt;Treat database design, authentication, and security as first‑class concerns, not afterthoughts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Why This Matters&lt;/li&gt;
&lt;li&gt;Mistake 1: Putting Too Much Logic in Controllers&lt;/li&gt;
&lt;li&gt;Mistake 2: Ignoring Eloquent Relationships and N+1 Queries&lt;/li&gt;
&lt;li&gt;Mistake 3: Poor Database Design and Indexing&lt;/li&gt;
&lt;li&gt;Mistake 4: Not Using Form Requests or Validation Properly&lt;/li&gt;
&lt;li&gt;Mistake 5: Ignoring Migrations and Model Structure&lt;/li&gt;
&lt;li&gt;Mistake 6: Messy Routes and Poor Naming Conventions&lt;/li&gt;
&lt;li&gt;Mistake 7: Overusing Helper/Static Methods and Global Helpers&lt;/li&gt;
&lt;li&gt;Mistake 8: Skipping Tests and Documentation&lt;/li&gt;
&lt;li&gt;Mistake 9: Hard‑coding Logic in Migrations or Seeders&lt;/li&gt;
&lt;li&gt;Mistake 10: Poor Error Handling and Logging&lt;/li&gt;
&lt;li&gt;Frequently Asked Questions (FAQs)&lt;/li&gt;
&lt;li&gt;Interesting Facts &amp;amp; Stats&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Why This Matters
&lt;/h2&gt;

&lt;p&gt;Laravel is designed to help you ship fast while keeping your codebase sane. But if you ignore structure, performance, and maintainability, your app can quickly become a “Laravel monolith” with tangled controllers, slow queries, and brittle validation.&lt;/p&gt;

&lt;p&gt;Common mistakes Laravel developers make often look harmless at first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A controller method that grows from 10 to 100 lines.&lt;/li&gt;
&lt;li&gt;A route file that crosses 500 lines.&lt;/li&gt;
&lt;li&gt;A model that eagerly loads every relation on every query.
These small decisions compound over time, leading to slower performance, harder debugging, and more expensive refactoring later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide helps you avoid the most common pitfalls and build Laravel apps that are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Readable to other developers&lt;/li&gt;
&lt;li&gt;Testable with clear separation of concerns&lt;/li&gt;
&lt;li&gt;Scalable as the user base and feature set grow&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Mistake 1: Putting Too Much Logic in Controllers
&lt;/h2&gt;

&lt;p&gt;Controllers are meant to handle HTTP concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accepting requests&lt;/li&gt;
&lt;li&gt;Running validation&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Returning responses&lt;br&gt;
When you put business logic directly in controllers, you end up with:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fat controllers anyone is afraid to touch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Duplicated logic across multiple controller methods&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hard‑to‑test code that depends on the HTTP request&lt;br&gt;
Example of the mistake:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SubscriptionController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;upgrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;user&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="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isPremium&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;back&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'You are already premium.'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'plan'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'annual'&lt;/span&gt;
            &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nv"&gt;$gateway&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;StripeGateway&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$gateway&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;charge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$price&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'premium'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;premium_until&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addYear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nf"&gt;event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserUpgraded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&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="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/dashboard'&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;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move charge and subscription logic into a &lt;code&gt;SubscriptionService&lt;/code&gt; or &lt;code&gt;SubscriptionAction&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Keep the controller action thin and focused on the request/response pipeline.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SubscriptionController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;upgrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;UpgradeSubscriptionAction&lt;/span&gt; &lt;span class="nv"&gt;$action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$action&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'plan'&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="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;back&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/dashboard'&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;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business logic is reusable across APIs, commands, and jobs.&lt;/li&gt;
&lt;li&gt;Easier to unit test the subscription logic without touching HTTP.&lt;/li&gt;
&lt;li&gt;Cleaner diffs and easier on‑boarding for new team members.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Mistake 2: Ignoring Eloquent Relationships and N+1 Queries
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Eloquent is powerful, but misuse kills performance.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many Laravel developers fetch data manually instead of using Eloquent relationships. This leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;N+1 queries (one query per related record)&lt;/li&gt;
&lt;li&gt;Slow page loads&lt;/li&gt;
&lt;li&gt;Database bottlenecks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example of the mistake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Each access triggers a separate query&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define relationships in your models (User belongsToMany Posts, etc.).&lt;/li&gt;
&lt;li&gt;Use with() to eager load related data.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// No extra query&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additional tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use select() to limit columns when you don’t need the full model.&lt;/li&gt;
&lt;li&gt;Avoid all() on large tables; paginate instead with paginate().&lt;/li&gt;
&lt;li&gt;Use tools like laravel-debugbar or clockwork to detect N+1 queries early.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Mistake 3: Poor Database Design and Indexing
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Bad database design will always be your bottleneck.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many Laravel apps start with poorly normalized tables, missing foreign keys, or no indexes on frequently queried columns. This leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slow queries&lt;/li&gt;
&lt;li&gt;Complex joins and filters in PHP instead of SQL&lt;/li&gt;
&lt;li&gt;Inconsistent or denormalized data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Common anti‑patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storing JSON in a single column instead of proper relationships&lt;/li&gt;
&lt;li&gt;Using integers for IDs but not defining foreign‑key constraints&lt;/li&gt;
&lt;li&gt;Not indexing columns used in where, order, or join clauses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Laravel migrations to define tables, indexes, and foreign keys.&lt;/li&gt;
&lt;li&gt;Normalize your data where it makes sense (e.g., users → posts → comments).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Index frequently filtered columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;foreignId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_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="nf"&gt;constrained&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster queries as datasets grow&lt;/li&gt;
&lt;li&gt;Easier to maintain data consistency&lt;/li&gt;
&lt;li&gt;Cleaner, more predictable Eloquent relationships&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Mistake 4: Not Using Form Requests or Validation Properly
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Validation should be reusable, not copy‑pasted.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Laravel’s validation is powerful, but it’s often embedded directly in controllers as inline arrays or repeated in multiple methods.&lt;/p&gt;

&lt;p&gt;Example of the mistake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required|email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'age'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'nullable|integer|min:18'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required|email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'age'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'nullable|integer|min:18'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="c1"&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;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create Form Request classes:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:request UserStoreRequest
php artisan make:request UserUpdateRequest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserStoreRequest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;FormRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required|unique:users,email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'age'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'nullable|integer|min:18'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then inject the form request into your controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UserStoreRequest&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validated&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validation rules are reusable and centralized&lt;/li&gt;
&lt;li&gt;You can add custom validation logic or authorization inside the form request&lt;/li&gt;
&lt;li&gt;Controllers stay lean and focused&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Mistake 5: Ignoring Migrations and Model Structure
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“They removed the model directory after the first migration.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Migrations are Laravel’s way to version‑control your database. Ignoring them or using them incorrectly leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Divergent schemas across environments&lt;/li&gt;
&lt;li&gt;Manual SQL changes in production&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Broken deployments&lt;br&gt;
Common mistakes:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not using down() methods in migrations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Writing business logic inside migration files (e.g., looping through users and updating them)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Skipping foreign keys or using unsigned() on integer foreign keys&lt;br&gt;
How to fix it:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Always define proper foreign keys:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;foreignId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_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="nf"&gt;constrained&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Use rollback‑safe migrations with clear up() and down() methods.&lt;/li&gt;
&lt;li&gt;Avoid complex business logic in migrations; move it to seeders or jobs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat migrations as “immutable” after they’re pushed to production.&lt;/li&gt;
&lt;li&gt;Use Schema::table() for alterations, not Schema::dropIfExists() for simple changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Mistake 6: Messy Routes and Poor Naming Conventions
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Routes are the contract of your app.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Laravel’s routing system is powerful, but it’s easy to end up with a monolithic routes/web.php file and inconsistently named routes.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Mixing API and web routes in one file&lt;/li&gt;
&lt;li&gt;Not using route groups (prefix, middleware, namespace)&lt;/li&gt;
&lt;li&gt;Using inconsistent route names like userShow, showUser, show_user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Split routes into:

&lt;ul&gt;
&lt;li&gt;routes/web.php (HTML pages)&lt;/li&gt;
&lt;li&gt;routes/api.php (REST or JSON endpoints)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Use route groups to apply middleware and prefixes:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'auth'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;UserController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'index'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'admin.users.index'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;UserController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'store'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'admin.users.store'&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;ul&gt;
&lt;li&gt;Follow consistent naming conventions (e.g.,
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="n"&gt;resource_route_name&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;snake_case&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;UserController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'index'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'index'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users/{user}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;UserController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'show'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'show'&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;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routes are easier to scan and maintain&lt;/li&gt;
&lt;li&gt;Route names are predictable for other developers&lt;/li&gt;
&lt;li&gt;Auth and middleware configuration is centralized&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Mistake 7: Overusing Helper/Static Methods and Global Helpers
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Helper methods are helpers, not your business logic.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many Laravel apps accumulate global helper functions in &lt;code&gt;app/Helpers&lt;/code&gt; or &lt;code&gt;config/helpers.php.&lt;/code&gt; This leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hidden dependencies and hard‑to‑trace behavior&lt;/li&gt;
&lt;li&gt;Testing nightmare (no dependency injection)&lt;/li&gt;
&lt;li&gt;Spaghetti‑style code scattered across functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use services, actions, or managers instead of global helpers.&lt;/li&gt;
&lt;li&gt;Use dependency injection where possible.
For example, instead of:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/Helpers/general.php&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;calculateDiscount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DiscountService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.9&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;Inject it into your controller or action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;DiscountService&lt;/span&gt; &lt;span class="nv"&gt;$discount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'price'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$discounted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$discount&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear dependencies and easier testing&lt;/li&gt;
&lt;li&gt;Reusable across services, jobs, and controllers&lt;/li&gt;
&lt;li&gt;Easier to refactor or replace logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. Mistake 8: Skipping Tests and Documentation
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Tests are your safety net.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Skipping tests leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fear of refactoring&lt;/li&gt;
&lt;li&gt;More bugs in production&lt;/li&gt;
&lt;li&gt;Longer on‑boarding for new developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write feature tests for critical user flows.&lt;/li&gt;
&lt;li&gt;Write unit tests for business logic and services.
Use Laravel’s built‑in testing helpers:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_user_can_upgrade_subscription&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'subscriptions.upgrade'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'plan'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'annual'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/dashboard'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;fresh&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isPremium&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;Best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use expectsDatabaseTransactions() for database‑intensive tests.&lt;/li&gt;
&lt;li&gt;Keep your tests fast and focused.&lt;/li&gt;
&lt;li&gt;Add high‑level documentation for architecture, routes, and key classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. Mistake 9: Hard‑coding Logic in Migrations or Seeders
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Migrations are not meant to run business logic.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;People sometimes write loops, call services, or send notifications inside migrations or seeders. This is dangerous because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Migrations are meant to be repeatable and safe to roll back&lt;/li&gt;
&lt;li&gt;Running business logic here can break future deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use migrations only for:

&lt;ul&gt;
&lt;li&gt;Schema changes&lt;/li&gt;
&lt;li&gt;Simple data seeding (if needed)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Move business logic into:

&lt;ul&gt;
&lt;li&gt;Artisan commands&lt;/li&gt;
&lt;li&gt;Jobs&lt;/li&gt;
&lt;li&gt;Seeders with proper rollback support&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:command MigrateOldUserSubscriptions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run it explicitly instead of hiding it in a migration.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Migrations stay predictable and safe&lt;/li&gt;
&lt;li&gt;Business logic can be retried or rolled back cleanly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  11. Mistake 10: Poor Error Handling and Logging
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Exceptions are information, not noise.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ignoring error handling and logging in Laravel apps leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Silent failures&lt;/li&gt;
&lt;li&gt;Difficult debugging in production&lt;/li&gt;
&lt;li&gt;Unpredictable behavior after exceptions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to fix it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use try/catch blocks where appropriate.&lt;/li&gt;
&lt;li&gt;Use Log::error(), Log::info(), or report() to log errors.&lt;/li&gt;
&lt;li&gt;Configure app/Exceptions/Handler.php to:

&lt;ul&gt;
&lt;li&gt;Report critical errors to services like Sentry, Bugsnag, or LogRocket&lt;/li&gt;
&lt;li&gt;Transform exceptions into user‑friendly messages&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Throwable&lt;/span&gt; &lt;span class="nv"&gt;$exception&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="nv"&gt;$exception&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;CustomException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Log or notify specific teams&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'slack'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exception&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;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easier debugging and faster incident response&lt;/li&gt;
&lt;li&gt;Better visibility into production issues&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12. Frequently Asked Questions (FAQs)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q. Should I always move logic from controllers to services?&lt;/strong&gt;&lt;br&gt;
A. Yes, if it’s reusable business logic. Keep controllers focused on HTTP concerns and use services, actions, or domain classes for the rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q. Is it okay to keep small apps without tests?&lt;/strong&gt;&lt;br&gt;
A. For small prototypes, maybe. But even tiny apps benefit from a basic test suite once they go to production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q. Can I mix web and API routes in one file?&lt;/strong&gt;&lt;br&gt;
A. Technically yes, but it’s cleaner to separate them into web.php and api.php with proper prefixing and middleware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q. Are migrations really necessary for small changes?&lt;/strong&gt;&lt;br&gt;
A. Yes, especially after going live. Migrations help keep your team and environment in sync.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q. How do I know if my app has N+1 queries?&lt;/strong&gt;&lt;br&gt;
A. Use tools like laravel-debugbar or clockwork to analyse queries or enable Laravel’s built‑in query logging in development.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. Interesting Facts &amp;amp; Stats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Well-structured Laravel apps with services, form requests, and proper Eloquent usage can reduce controller code by 40-60% in larger projects. Source: &lt;a href="https://laravel.com/docs/eloquent-resources" rel="noopener noreferrer"&gt;https://laravel.com/docs/eloquent-resources&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Teams that consistently use migrations and tests spend 25-35% less time debugging in production compared to teams that don’t.
Source: &lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html" rel="noopener noreferrer"&gt;https://martinfowler.com/articles/practical-test-pyramid.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Avoiding N+1 queries often reduces page load time by 2-10x for list-style pages with relationships.Source: &lt;a href="https://laravel.com/docs/eloquent-relationships#eager-loading" rel="noopener noreferrer"&gt;https://laravel.com/docs/eloquent-relationships#eager-loading&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Laravel’s Form Request system and built-in validation rules have become industry standards for clean, maintainable validation logic in web frameworks.Source: &lt;a href="https://laravel.com/docs/validation" rel="noopener noreferrer"&gt;https://laravel.com/docs/validation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Laravel is a powerful framework that encourages fast development, but it also amplifies the impact of bad habits. Common mistakes like fat controllers, poor database design, and ignoring migrations can slow your app and your team over time.&lt;/p&gt;

&lt;p&gt;By consistently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Moving business logic out of controllers&lt;/li&gt;
&lt;li&gt;Using Eloquent properly and avoiding N+1 queries&lt;/li&gt;
&lt;li&gt;Organizing routes, migrations, and helpers&lt;/li&gt;
&lt;li&gt;Writing tests and proper logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You turn Laravel’s “easy to start” advantage into a long‑term maintenance win.&lt;/p&gt;

&lt;p&gt;Clean, maintainable Laravel code is not about syntax alone; it’s about structure, separation of concerns, and respecting the framework’s conventions. Stick to these patterns, and you’ll avoid most of the common pitfalls Laravel developers face in production.&lt;/p&gt;

&lt;p&gt;About the Author: &lt;em&gt;Lakashya is a full‑stack Laravel developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWeb Solution&lt;/a&gt; specializing in scalable, real‑time applications with PHP and modern frontends.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Laravel Documentation. (2025). Best Practices. 
&lt;a href="https://laravel.com/docs/12.x%E2%80%8B" rel="noopener noreferrer"&gt;https://laravel.com/docs/12.x​&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Laravel.io. (2026). Common Laravel Mistakes I See in Production. &lt;a href="https://laravel.io/articles/common-laravel-mistakes-i-see-in-production-and-how-to-avoid-them" rel="noopener noreferrer"&gt;https://laravel.io/articles/common-laravel-mistakes-i-see-in-production-and-how-to-avoid-them&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Laravel Daily. (2025). Laravel: 9 Typical Mistakes Juniors Make. &lt;a href="https://laraveldaily.com/post/laravel-typical-mistakes-juniors-make" rel="noopener noreferrer"&gt;https://laraveldaily.com/post/laravel-typical-mistakes-juniors-make&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>laravelbestpractices</category>
      <category>laravelmistakes</category>
      <category>phpdevelopment</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>Practical Techniques for Optimizing React Performance in Production: A Developer’s Guide</title>
      <dc:creator>Mayank Goyal</dc:creator>
      <pubDate>Thu, 26 Mar 2026 10:34:57 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/practical-techniques-for-optimizing-react-performance-in-production-a-developers-guide-ho0</link>
      <guid>https://dev.to/addwebsolutionpvtltd/practical-techniques-for-optimizing-react-performance-in-production-a-developers-guide-ho0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Premature optimization is the root of all evil." - Donald Knuth&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As modern web applications grow in complexity, maintaining high performance becomes increasingly important. React is known for its efficient rendering and component-based architecture, but poorly optimized applications can still suffer from issues such as slow rendering, unnecessary re-renders, large bundle sizes, and delayed user interactions.&lt;/p&gt;

&lt;p&gt;Optimizing React applications in production environments requires a combination of architectural decisions, efficient state management, and performance monitoring.&lt;/p&gt;

&lt;p&gt;This guide explores practical techniques developers can use to optimize React performance in production, helping applications remain fast, scalable, and responsive even as they grow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Avoid unnecessary component re-renders using React.memo, useMemo, and useCallback.&lt;/li&gt;
&lt;li&gt;Use code splitting and lazy loading to reduce initial bundle size.&lt;/li&gt;
&lt;li&gt;Implement list virtualization when rendering large datasets.&lt;/li&gt;
&lt;li&gt;Optimize state management to prevent unnecessary updates.&lt;/li&gt;
&lt;li&gt;Use debouncing and throttling for expensive operations like search or scroll events.&lt;/li&gt;
&lt;li&gt;Regularly monitor performance using React DevTools and browser profiling tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Understanding React Performance Optimization&lt;/li&gt;
&lt;li&gt;Detailed Comparison of Optimization Techniques&lt;/li&gt;
&lt;li&gt;Implementation Overview&lt;/li&gt;
&lt;li&gt;When to Use Each Optimization Strategy&lt;/li&gt;
&lt;li&gt;Developer Recommendations&lt;/li&gt;
&lt;li&gt;Code Examples&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Understanding React Performance Optimization
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.1 Preventing Unnecessary Re-Renders&lt;/strong&gt;&lt;br&gt;
React re-renders components whenever their state or props change. While React's Virtual DOM minimizes DOM updates, unnecessary re-renders can still affect performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Techniques&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React.memo&lt;/strong&gt;&lt;br&gt;
Prevents functional components from re-rendering when props have not changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;useMemo&lt;/strong&gt;&lt;br&gt;
Caches the result of expensive computations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;useCallback&lt;/strong&gt;&lt;br&gt;
Prevents functions from being recreated on every render.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components that render frequently&lt;/li&gt;
&lt;li&gt;Expensive calculations inside components&lt;/li&gt;
&lt;li&gt;Preventing unnecessary child component updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;1.2 Code Splitting and Lazy Loading&lt;/strong&gt;&lt;br&gt;
Large JavaScript bundles increase page load time and negatively impact performance.&lt;br&gt;
Code splitting allows loading only the code required for the current view.&lt;br&gt;
React provides built-in support through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React.lazy&lt;/li&gt;
&lt;li&gt;Suspense&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefits&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster initial page load&lt;/li&gt;
&lt;li&gt;Reduced bundle size&lt;/li&gt;
&lt;li&gt;Improved performance on slower networks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large applications&lt;/li&gt;
&lt;li&gt;Route-based components&lt;/li&gt;
&lt;li&gt;Feature-heavy dashboards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;1.3 Virtualizing Large Lists&lt;/strong&gt;&lt;br&gt;
Rendering thousands of DOM elements simultaneously can slow down the browser.&lt;br&gt;
List virtualization renders only the items visible in the viewport.&lt;br&gt;
Popular libraries include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;react-window&lt;/li&gt;
&lt;li&gt;react-virtualized&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large tables&lt;/li&gt;
&lt;li&gt;Infinite scrolling lists&lt;/li&gt;
&lt;li&gt;Analytics dashboards&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  2. Detailed Comparison
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;2.1 Rendering Optimization&lt;/strong&gt;&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%2F5wm3lmgyv09oyqno9ypg.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%2F5wm3lmgyv09oyqno9ypg.png" alt=" " width="631" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.2 Bundle Optimization&lt;/strong&gt;&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%2F90qrn5p9prflrgit9os7.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%2F90qrn5p9prflrgit9os7.png" alt=" " width="551" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.3 Event Optimization&lt;/strong&gt;&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%2Fbv8fa13queapqzubiqum.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%2Fbv8fa13queapqzubiqum.png" alt=" " width="539" height="149"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Implementation Overview
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;3.1 Memoizing Components&lt;/strong&gt;&lt;br&gt;
Flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Component receives props&lt;/li&gt;
&lt;li&gt;React compares previous and new props&lt;/li&gt;
&lt;li&gt;If props are unchanged, rendering is skipped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduces unnecessary rendering&lt;/li&gt;
&lt;li&gt;Improves UI responsiveness&lt;/li&gt;
&lt;li&gt;Useful in component-heavy applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3.2 Code Splitting in React&lt;/strong&gt;&lt;br&gt;
Flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User visits application&lt;/li&gt;
&lt;li&gt;Initial bundle loads&lt;/li&gt;
&lt;li&gt;Additional components load on demand&lt;/li&gt;
&lt;li&gt;Suspense displays fallback UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster application startup&lt;/li&gt;
&lt;li&gt;Reduced network usage&lt;/li&gt;
&lt;li&gt;Better scalability for large apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3.3 Virtualizing Lists&lt;/strong&gt;&lt;br&gt;
Flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large dataset fetched&lt;/li&gt;
&lt;li&gt;Only visible rows rendered&lt;/li&gt;
&lt;li&gt;Rows dynamically mounted/unmounted during scroll&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduces DOM nodes&lt;/li&gt;
&lt;li&gt;Smooth scrolling&lt;/li&gt;
&lt;li&gt;Improves memory usage&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  4. When to Use Each Optimization Technique
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use Memoization If&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components render frequently&lt;/li&gt;
&lt;li&gt;Parent components trigger unnecessary updates&lt;/li&gt;
&lt;li&gt;Expensive calculations occur during rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Code Splitting If&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your bundle size is large&lt;/li&gt;
&lt;li&gt;Your app has multiple pages&lt;/li&gt;
&lt;li&gt;You want faster initial load time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Virtualization If&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rendering thousands of items&lt;/li&gt;
&lt;li&gt;Working with large datasets&lt;/li&gt;
&lt;li&gt;Building analytics dashboards or tables&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  5. Developer Recommendation
&lt;/h2&gt;

&lt;p&gt;For most production React applications, the following performance practices provide the biggest impact:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Memoize components when necessary&lt;/li&gt;
&lt;li&gt;Implement route-based code splitting&lt;/li&gt;
&lt;li&gt;Use virtualization for large lists&lt;/li&gt;
&lt;li&gt;Debounce expensive API requests&lt;/li&gt;
&lt;li&gt;Continuously monitor performance using profiling tools&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Optimizing too early can introduce unnecessary complexity, so focus first on identifying performance bottlenecks before applying optimizations.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Code Examples
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;6.1 Preventing Re-renders with React.memo&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&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;UserCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rendering UserCard&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;UserCard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.2 Using useMemo for Expensive Calculations&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMemo&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="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ExpensiveComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&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;sortedItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&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;return&lt;/span&gt; &lt;span class="nx"&gt;items&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="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&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;items&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sortedItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.3 Lazy Loading Components&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Suspense&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="s2"&gt;react&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;Dashboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.4 Debouncing API Calls&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;debounce&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash/debounce&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;searchUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;debounce&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;query&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;response&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;`/api/users?q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. What causes poor React performance?&lt;/strong&gt;&lt;br&gt;
Common causes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unnecessary re-renders&lt;/li&gt;
&lt;li&gt;Large bundle sizes&lt;/li&gt;
&lt;li&gt;Rendering large lists&lt;/li&gt;
&lt;li&gt;Heavy computations during rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Should every component use React.memo?&lt;/strong&gt;&lt;br&gt;
No. Memoization adds comparison overhead. Use it only when performance issues exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What tool helps identify slow components?&lt;/strong&gt;&lt;br&gt;
React DevTools Profiler helps identify slow rendering components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Is lazy loading good for SEO?&lt;/strong&gt;&lt;br&gt;
It can be, but server-side rendering (SSR) may be required for SEO-critical pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. What is the biggest performance win in React apps?&lt;/strong&gt;&lt;br&gt;
Reducing bundle size and unnecessary re-renders typically provides the largest improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;React’s Virtual DOM reduces direct DOM manipulation by updating only the elements that changed.Source:&lt;a href="https://react.dev/learn/render-and-commit" rel="noopener noreferrer"&gt;https://react.dev/learn/render-and-commit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The React Profiler tool allows developers to measure rendering performance and detect unnecessary updates.Source:&lt;a href="https://react.dev/reference/react/Profiler" rel="noopener noreferrer"&gt;https://react.dev/reference/react/Profiler&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Libraries like react-window can reduce thousands of DOM nodes to just a few dozen visible elements.Source:&lt;a href="https://github.com/bvaughn/react-window" rel="noopener noreferrer"&gt;https://github.com/bvaughn/react-window&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;"Programs must be written for people to read, and only incidentally for machines to execute." – Harold Abelson&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Optimizing React performance in production requires thoughtful architecture and strategic use of optimization techniques. While React already provides efficient rendering through the Virtual DOM, developers must still manage component updates, bundle sizes, and expensive computations carefully.&lt;/p&gt;

&lt;p&gt;By applying techniques such as memoization, code splitting, virtualization, and event optimization, developers can significantly improve application responsiveness and scalability.&lt;br&gt;
The key is to identify real performance bottlenecks first and apply targeted optimizations, ensuring the application remains both maintainable and performant.&lt;/p&gt;

&lt;p&gt;About the Author: &lt;em&gt;Mayank is a web developer at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;, building scalable apps with PHP, Node.js &amp;amp; React. Sharing ideas, code, and creativity.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactjsdevelopment</category>
      <category>performance</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Secure File Uploads in Laravel: Validation, Storage &amp; Basic Virus Protection</title>
      <dc:creator>Abodh Kumar</dc:creator>
      <pubDate>Fri, 20 Mar 2026 07:54:18 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/secure-file-uploads-in-laravel-validation-storage-basic-virus-protection-1hb4</link>
      <guid>https://dev.to/addwebsolutionpvtltd/secure-file-uploads-in-laravel-validation-storage-basic-virus-protection-1hb4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Security is not a product, but a process.- Bruce Schneier, Security Technologist&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;File uploads are a common requirement in modern web applications - whether it's profile pictures, documents, invoices, or media files. However, insecure file uploads can expose your application to serious threats such as malware injection, remote code execution, and data breaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Validate both file extension (mimes) and content-based MIME type (mimetypes) - never trust one alone.&lt;/li&gt;
&lt;li&gt;Always generate a random UUID-based filename - never persist client-supplied filenames to disk.&lt;/li&gt;
&lt;li&gt;Store files outside the public directory on a private disk; serve through authenticated controllers.&lt;/li&gt;
&lt;li&gt;Use temporary signed URLs for file downloads to prevent unauthorized access and link sharing.&lt;/li&gt;
&lt;li&gt;Integrate ClamAV or another AV engine; fail closed if the scanner is unavailable.&lt;/li&gt;
&lt;li&gt;Strip EXIF metadata from images to protect user privacy and prevent location data leaks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Understanding File Upload Risks&lt;/li&gt;
&lt;li&gt;Laravel File Validation - A Deep Dive&lt;/li&gt;
&lt;li&gt;Secure Storage Strategies&lt;/li&gt;
&lt;li&gt;Basic Virus Protection with ClamAV&lt;/li&gt;
&lt;li&gt;Advanced Security Techniques&lt;/li&gt;
&lt;li&gt;Stats &amp;amp; Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;document managers to medical portals and e-commerce platforms. Yet despite their ubiquity, secure file handling remains one of the most misunderstood areas of web development.&lt;/p&gt;

&lt;p&gt;Laravel, PHP's premier web framework, equips developers with an elegant and expressive set of tools for handling file uploads. However, leveraging those tools securely requires a deliberate, layered approach: validating the incoming file, storing it safely, and scanning it for malicious content before it ever reaches your users or your system.&lt;/p&gt;

&lt;p&gt;This article walks you through a complete, production-ready strategy for secure file uploads in Laravel - covering everything from MIME type validation and file size limits to randomized storage paths and ClamAV antivirus integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Understanding File Upload Risks
&lt;/h2&gt;

&lt;p&gt;Before writing a single line of code, it is essential to understand why file uploads are dangerous. Attackers routinely exploit careless upload implementations to compromise servers and steal data. The most common attack vectors include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.1  Malicious File Execution&lt;/strong&gt;&lt;br&gt;
An attacker uploads a PHP file disguised as an image (e.g., evil.php.jpg). If the server is misconfigured or the MIME type is not properly validated, the file may be executed as a script, granting the attacker remote code execution (RCE).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.2  Denial of Service via Large Uploads&lt;/strong&gt;&lt;br&gt;
Without file size restrictions, an attacker can upload multi-gigabyte files to exhaust disk space or memory, effectively taking down the server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.3  Path Traversal Attacks&lt;/strong&gt;&lt;br&gt;
If user-supplied filenames are stored directly, an attacker might submit a filename like ../../etc/passwd to write or overwrite sensitive files on the server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.4  Virus &amp;amp; Malware Distribution&lt;/strong&gt;&lt;br&gt;
Even with correct validation, a seemingly valid PDF or DOCX file might contain embedded malware. If your application serves these files to other users, you inadvertently become a malware distribution vector.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.5  Metadata &amp;amp; Privacy Leaks&lt;/strong&gt;&lt;br&gt;
Uploaded images may contain EXIF metadata including GPS coordinates, device information, or personally identifiable information - a significant privacy risk if files are served publicly without stripping metadata.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Laravel File Validation - A Deep Dive
&lt;/h2&gt;

&lt;p&gt;Laravel's validation system is remarkably expressive. The file() and image() validation rules, combined with additional constraints, let you define exactly what constitutes an acceptable upload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.1  Basic Validation Setup&lt;/strong&gt;&lt;br&gt;
Start with a dedicated Form Request class to keep your controller lean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    php artisan make:request SecureFileUploadRequest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your SecureFileUploadRequest class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Requests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Http\FormRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecureFileUploadRequest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;FormRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;authorize&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&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="s1"&gt;'document'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
               &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s1"&gt;'file'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s1"&gt;'mimes:pdf,docx,xlsx,png,jpg,jpeg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s1"&gt;'mimetypes:application/pdf,image/png,image/jpeg,
                          application/vnd.openxmlformats-officedocument
                          .wordprocessingml.document'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s1"&gt;'max:10240'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
               &lt;span class="s1"&gt;'min:1'&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&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="s1"&gt;'document.mimes'&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Only PDF, DOCX, XLSX, PNG, and JPG                   files are allowed.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s1"&gt;'document.max'&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'File size must not exceed 10 MB.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s1"&gt;'document.mimetypes'&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The file type does not match the expected MIME type.'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.2  Understanding mimes vs. mimetypes&lt;/strong&gt;&lt;br&gt;
This is a common source of confusion. The mimes rule validates using the file extension, while mimetypes validates the actual MIME type detected by PHP's Fileinfo extension. Using both together is a stronger approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mimes:pdf,png - Laravel maps the extension to an expected MIME type and checks it.&lt;/li&gt;
&lt;li&gt;mimetypes:application/pdf - Directly checks the MIME type detected from file content.&lt;/li&gt;
&lt;li&gt;Using both ensures neither the extension nor the MIME type is spoofed independently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3.3  Validating Dimensions for Images&lt;/strong&gt;&lt;br&gt;
For image uploads specifically, Laravel allows you to enforce dimension constraints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'avatar'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s1"&gt;'image'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s1"&gt;'mimes:jpeg,png,webp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s1"&gt;'max:2048'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s1"&gt;'dimensions:min_width=100,min_height=100,max_width=3000,max_height=3000'&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;
  
  
  4. Secure Storage Strategies
&lt;/h2&gt;

&lt;p&gt;Validating a file is only half the battle. Where and how you store it is equally critical to your application's security posture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.1  Never Store in the Public Directory&lt;/strong&gt;&lt;br&gt;
A common beginner mistake is storing uploads directly in public/uploads. This makes files web-accessible by default, which is dangerous. Use the storage/app/private directory instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Storage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;SecureFileUploadRequest&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'document'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="nv"&gt;$filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Str&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getClientOriginalExtension&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;storeAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="s1"&gt;'uploads/'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
       &lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s1"&gt;'private'&lt;/span&gt; 
   &lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
       &lt;span class="s1"&gt;'user_id'&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
       &lt;span class="s1"&gt;'original_name'&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getClientOriginalName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
       &lt;span class="s1"&gt;'stored_path'&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s1"&gt;'mime_type'&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMimeType&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
       &lt;span class="s1"&gt;'file_size'&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getSize&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
   &lt;span class="p"&gt;]);&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'File uploaded successfully.'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.2  Configuring a Private Disk&lt;/strong&gt;&lt;br&gt;
In config/filesystems.php, define a private disk that lives outside the public web root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'disks'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="s1"&gt;'private'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
       &lt;span class="s1"&gt;'driver'&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'local'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s1"&gt;'root'&lt;/span&gt;       &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;storage_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'app/private'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="s1"&gt;'visibility'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'private'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;],&lt;/span&gt;
   &lt;span class="s1"&gt;'s3_private'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
       &lt;span class="s1"&gt;'driver'&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'s3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s1"&gt;'key'&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AWS_ACCESS_KEY_ID'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="s1"&gt;'secret'&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AWS_SECRET_ACCESS_KEY'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="s1"&gt;'region'&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AWS_DEFAULT_REGION'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="s1"&gt;'bucket'&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AWS_BUCKET'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="s1"&gt;'visibility'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'private'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Never trust user input when handling uploaded files. Always validate file types, sizes, and storage locations on the server side.- Stephen Rees-Carter&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;4.3  Serving Files Securely via Signed URLs&lt;/strong&gt;&lt;br&gt;
Since files are not publicly accessible, you need a controller endpoint to serve them. Use signed URLs to prevent unauthorized access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Illuminate\Support\Facades\URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$signedUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;temporarySignedRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="s1"&gt;'file.download'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'document'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$document&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/files/{document}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Document&lt;/span&gt; &lt;span class="nv"&gt;$document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;abort_unless&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasValidSignature&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
       &lt;span class="nv"&gt;$document&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
       &lt;span class="mi"&gt;403&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Storage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'private'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$document&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;stored_path&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="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'file.download'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'auth'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'signed'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Basic Virus Protection with ClamAV
&lt;/h2&gt;

&lt;p&gt;Even perfectly validated files can harbor malicious payloads. A PDF can contain JavaScript exploits; a DOCX can embed macros. Integrating an antivirus scanner is the professional-grade answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.1  Installing ClamAV&lt;/strong&gt;&lt;br&gt;
On Ubuntu/Debian servers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; clamav clamav-daemon
&lt;span class="nb"&gt;sudo &lt;/span&gt;freshclam   &lt;span class="c"&gt;# Update virus definitions&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;clamav-daemon
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start clamav-daemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.2  Using the Laravel ClamAV Package&lt;/strong&gt;&lt;br&gt;
The most popular Laravel integration is via the laravel-clamav package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require clamav/clamav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use a custom wrapper with the PHP socket connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require sunspikes/clamav-validator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.3  Building a ClamAV Service&lt;/strong&gt;&lt;br&gt;
Here is a clean, reusable ClamAV service class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\UploadedFile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VirusScanService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$clamdHost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$clamdPort&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;clamdHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'services.clamav.host'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'127.0.0.1'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;clamdPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'services.clamav.port'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3310&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UploadedFile&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nv"&gt;$socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;fsockopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;clamdHost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;clamdPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="nv"&gt;$errno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="nv"&gt;$errstr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="mi"&gt;5&lt;/span&gt;
       &lt;span class="p"&gt;);&lt;/span&gt;

       &lt;span class="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="nv"&gt;$socket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ClamAV unavailable'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'error'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$errstr&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
           &lt;span class="c1"&gt;// Fail closed: reject upload if scanner unavailable&lt;/span&gt;
           &lt;span class="k"&gt;return&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="nv"&gt;$fileContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getRealPath&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
       &lt;span class="nv"&gt;$length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fileContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

       &lt;span class="nb"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"nINSTREAM&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nb"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'N'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$fileContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nb"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'N'&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="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;fgets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$socket&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
       &lt;span class="nb"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$socket&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="c1"&gt;// 'stream: OK' means clean; anything else is infected&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;str_contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'OK'&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;&lt;strong&gt;5.4  Integrating the Scanner in Your Controller&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Services\VirusScanService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;SecureFileUploadRequest&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;VirusScanService&lt;/span&gt; &lt;span class="nv"&gt;$scanner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'document'&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="nv"&gt;$scanner&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
           &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'File rejected: security scan failed.'&lt;/span&gt;
       &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Allowing unrestricted file uploads can lead to remote code execution if attackers manage to upload executable scripts to the server.- OWASP Security Guidelines&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  6. Advanced Security Techniques
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;6.1  Strip EXIF Metadata from Images&lt;/strong&gt;&lt;br&gt;
Use the intervention/image package to remove sensitive metadata from uploaded images before storage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require intervention/image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Intervention\Image\Facades\Image&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getRealPath&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="c1"&gt;// Strip all EXIF data by re-encoding&lt;/span&gt;
&lt;span class="nv"&gt;$cleanImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$image&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jpg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Storage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'private'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$cleanImage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.2  Implement Rate Limiting on Upload Endpoints&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In routes/api.php&lt;/span&gt;
&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'auth'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'throttle:10,1'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  &lt;span class="c1"&gt;// 10 uploads per minute&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/upload'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;FileController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'store'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.3  Queue Virus Scans for Large Files&lt;/strong&gt;&lt;br&gt;
For large files, run the virus scan asynchronously to avoid request timeouts:&lt;/p&gt;

&lt;p&gt;// Create a job&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:job ScanUploadedFile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Dispatch after initial upload&lt;/span&gt;
&lt;span class="nc"&gt;ScanUploadedFile&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$document&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&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="nf"&gt;onQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'scans'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6.4  Content Security Headers&lt;/strong&gt;&lt;br&gt;
Even with secure storage, add these HTTP headers when serving files to prevent browsers from executing served content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withHeaders&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
   &lt;span class="s1"&gt;'X-Content-Type-Options'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'nosniff'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s1"&gt;'Content-Disposition'&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'attachment; filename="'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$filename&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'"'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s1"&gt;'X-Frame-Options'&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'DENY'&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;
  
  
  7.Stats &amp;amp; Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;According to the Veracode State of Software Security Report, file upload vulnerabilities are responsible for a significant portion of web application security flaws, with around 12% of critical vulnerabilities related to improper file handling.Source: &lt;a href="https://www.veracode.com/resources/reports/state-of-software-security-report" rel="noopener noreferrer"&gt;https://www.veracode.com/resources/reports/state-of-software-security-report&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The OWASP Top 10 highlights insecure file upload mechanisms as a common cause of Remote Code Execution (RCE) attacks when applications fail to properly validate file types and storage paths.
Source: &lt;a href="https://owasp.org/www-project-top-ten/" rel="noopener noreferrer"&gt;https://owasp.org/www-project-top-ten/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Research shows that attackers often bypass validation by disguising malicious scripts as image or PDF files, such as renaming a .php file to .jpg or .png.Source: &lt;a href="https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload" rel="noopener noreferrer"&gt;https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Malware scanning systems like ClamAV can detect up to 98% of known malware signatures, making antivirus scanning a useful additional layer for file upload security.Source: &lt;a href="https://www.clamav.net/documents/clamav-user-manual" rel="noopener noreferrer"&gt;https://www.clamav.net/documents/clamav-user-manual&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;According to security studies, allowing unrestricted file sizes can lead to Denial-of-Service (DoS) attacks, where attackers intentionally upload large files to exhaust server disk space.Source: &lt;a href="https://owasp.org/www-community/attacks/Denial_of_Service" rel="noopener noreferrer"&gt;https://owasp.org/www-community/attacks/Denial_of_Service&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;According to cybersecurity research, over 90% of successful web attacks exploit known vulnerabilities that could have been prevented through proper validation and secure configuration practices.Source: &lt;a href="https://www.verizon.com/business/resources/reports/dbir/" rel="noopener noreferrer"&gt;https://www.verizon.com/business/resources/reports/dbir/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;According to the SANS Institute, improper file upload validation is one of the most common ways attackers upload web shells, which can allow them to execute commands on the server and gain full control of the application.Source: &lt;a href="https://www.sans.org/white-papers/" rel="noopener noreferrer"&gt;https://www.sans.org/white-papers/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Why is file upload security important in Laravel?&lt;/strong&gt;&lt;br&gt;
Ans: File upload security is important because attackers can upload malicious files such as scripts or malware. If the application does not properly validate and store files, it may lead to serious vulnerabilities like Remote Code Execution (RCE), data theft, or server compromise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. How can Laravel validate uploaded files?&lt;/strong&gt;&lt;br&gt;
Ans: Laravel provides built-in validation rules such as mimes, mimetypes, max, and file. These rules help ensure that only allowed file types and sizes are uploaded, reducing the risk of malicious files entering the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Where should uploaded files be stored in Laravel?&lt;/strong&gt;&lt;br&gt;
Ans: Uploaded files should ideally be stored in the storage directory instead of the public directory. Laravel’s Storage system helps manage files securely and prevents direct execution of uploaded files on the server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. How can I limit the file size in Laravel uploads?&lt;/strong&gt;&lt;br&gt;
Ans: You can limit file size using the max validation rule in Laravel. For example:&lt;br&gt;
'file' =&amp;gt; 'required|mimes:jpg,png,pdf|max:2048'&lt;br&gt;
 This restricts uploads to specific file types and a maximum size of 2MB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Can Laravel scan uploaded files for viruses?&lt;/strong&gt;&lt;br&gt;
Ans: Laravel does not include built-in antivirus scanning, but you can integrate tools like ClamAV or third-party security services to scan uploaded files before storing or processing them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. What are some best practices for secure file uploads?&lt;/strong&gt;&lt;br&gt;
Ans: Best practices include validating file types, restricting file sizes, renaming uploaded files, storing them outside the public directory, scanning for malware, and setting proper file permissions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. How can attackers bypass file upload validation?&lt;/strong&gt;&lt;br&gt;
Ans: Attackers may rename malicious files to appear as safe formats (e.g., .php to .jpg) or manipulate MIME types. This is why multiple validation layers and secure storage practices are important.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Does Laravel provide protection against malicious file execution?&lt;/strong&gt;&lt;br&gt;
Ans: Laravel helps reduce risk through validation and secure storage systems, but developers must still implement proper validation, file renaming, and server configuration to fully protect against malicious file execution.&lt;/p&gt;

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

&lt;p&gt;Secure file uploads are not a feature - they are a discipline. Every layer described in this article serves a specific purpose in a defense-in-depth strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validation catches malformed or unexpected files before they enter your system.&lt;/li&gt;
&lt;li&gt;Secure storage ensures that even if validation is bypassed, files cannot be executed.&lt;/li&gt;
&lt;li&gt;Virus scanning adds a safety net against sophisticated threats that evade other checks.&lt;/li&gt;
&lt;li&gt;Rate limiting, signed URLs, and HTTP security headers complete the picture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Laravel provides all the building blocks you need. The responsibility lies with developers to connect them thoughtfully, test them rigorously, and stay current with evolving attack patterns.&lt;/p&gt;

&lt;p&gt;Security is never a one-time setup. Regularly update ClamAV virus definitions, review your validation rules when you add new file types, and audit your storage access logs. A breach avoided is invisible - and that invisibility is the mark of excellent security engineering.&lt;/p&gt;

&lt;p&gt;About the Author: &lt;em&gt;Abodh is a PHP and Laravel Developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWeb Solution&lt;/a&gt;, skilled in MySQL, REST APIs, JavaScript, Git, and Docker for building robust web applications.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>laravelsecurity</category>
      <category>phpsecurity</category>
      <category>fileupload</category>
    </item>
  </channel>
</rss>
