<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[FullStack Unlocked]]></title><description><![CDATA[every thing you need to know about full stack development ]]></description><link>https://blog.suprabhat.site</link><image><url>https://cdn.hashnode.com/uploads/logos/67878f19cf0699455cef774d/59ae8dfd-115d-4555-8c03-e254bc1fe7eb.jpg</url><title>FullStack Unlocked</title><link>https://blog.suprabhat.site</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 10 May 2026 19:55:24 GMT</lastBuildDate><atom:link href="https://blog.suprabhat.site/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Handling File Uploads in Express with Multer]]></title><description><![CDATA[Across the web, almost every modern application needs to handle file uploads. Whether it is a profile picture, a resume, or a product image, users expect to upload files smoothly. But if you have ever]]></description><link>https://blog.suprabhat.site/handling-file-uploads-in-express-with-multer</link><guid isPermaLink="true">https://blog.suprabhat.site/handling-file-uploads-in-express-with-multer</guid><category><![CDATA[multer]]></category><category><![CDATA[File Upload]]></category><category><![CDATA[Express]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sun, 03 May 2026 16:28:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/73e73d1f-9a56-4453-aae6-30a01b76f95b.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Across the web, almost every modern application needs to handle file uploads. Whether it is a profile picture, a resume, or a product image, users expect to upload files smoothly. But if you have ever tried handling file uploads in Express.js, you might have noticed that Express does not process them out of the box.</p>
<p>In this blog we will understand why file uploads need middleware, what Multer is, how to handle single and multiple file uploads, how to configure storage properly, and how to serve uploaded files back to users.</p>
<p>First, let’s understand why file uploads need middleware.</p>
<h2>Why File Uploads Need Middleware</h2>
<p>When a standard HTML form submits text data, browsers usually send it as <code>application/x-www-form-urlencoded</code> or <code>application/json</code>. Express can parse these formats easily using built-in middleware like <code>express.json()</code> or <code>express.urlencoded()</code>. But files are completely different.</p>
<p>Browsers send files using <code>multipart/form-data</code>. This format splits the request into multiple parts: text fields, file metadata, and the actual binary file stream. Express does not parse <code>multipart/form-data</code> by default. If you try to access <code>req.body</code> or <code>req.files</code> without middleware, you will get <code>undefined</code>.</p>
<p>That is where middleware comes in. It intercepts the incoming request, reads the multipart stream, extracts the files safely, and attaches them to the request object. Without this step, your server would have to manually handle binary chunks, manage temporary files, and prevent memory leaks. Middleware abstracts all of that complexity so you can focus on your application logic.</p>
<p>Now let’s understand what Multer is.</p>
<h2>What is Multer?</h2>
<p>Multer is a Node.js middleware built specifically for handling <code>multipart/form-data</code>. It is the most popular and widely recommended solution for file uploads in Express.</p>
<p>Multer parses incoming requests, extracts files, and gives you full control over where and how those files are stored. It also provides built-in safety features like file size limits, field validation, and error handling. Without Multer, you would need to write custom stream parsers, manage disk cleanup, and handle edge cases manually. Multer turns a complex, error-prone process into a few lines of clean configuration.</p>
<p>Before we upload anything, we need to decide where files should go.</p>
<h2>Storage Configuration Basics</h2>
<p>Multer gives you two main storage engines: memory storage and disk storage.</p>
<p>Memory storage keeps uploaded files in RAM as <code>Buffer</code> objects. It is fast and useful for small files or when you want to pipe data directly to cloud storage. But it is not safe for production apps because large uploads can exhaust your server memory and crash the process.</p>
<p>Disk storage saves files directly to your server’s file system. This is the recommended approach for most beginners and small-to-medium projects. You configure it using <code>multer.diskStorage()</code>, where you define two things:</p>
<ul>
<li><p><code>destination</code>: The folder where files will be saved</p>
</li>
<li><p><code>filename</code>: How the saved file should be named</p>
</li>
</ul>
<p>By default, Multer generates random filenames without extensions. To keep things organized, you can preserve the original extension, add timestamps, or generate unique IDs. Proper filename configuration prevents collisions and makes future file management much easier.</p>
<p>Now let’s understand how to handle a single file upload.</p>
<h2>Handling Single File Upload</h2>
<p>Once Multer is installed (<code>npm install multer</code>) and storage is configured, you can attach it to your routes as middleware.</p>
<p>For a single file, you use <code>upload.single('fieldName')</code>. The <code>fieldName</code> must match the <code>name</code> attribute in your HTML form or frontend API request. When the request reaches your route, Multer processes the file, saves it to disk, and attaches metadata to <code>req.file</code>.</p>
<p>You can then access useful properties like:</p>
<ul>
<li><p><code>req.file.filename</code>: The saved name on disk</p>
</li>
<li><p><code>req.file.path</code>: The full file path</p>
</li>
<li><p><code>req.file.size</code>: File size in bytes</p>
</li>
<li><p><code>req.file.mimetype</code>: The detected file type</p>
</li>
</ul>
<p>If the field is missing or the file exceeds your configured limits, Multer throws an error that you can catch and return as a clean JSON response. This makes single file uploads predictable, secure, and easy to debug.</p>
<p>What if users need to upload more than one file?</p>
<h2>Handling Multiple File Uploads</h2>
<p>Multer handles multiple uploads smoothly without changing your core setup.</p>
<p>If users upload several files from the same form field, use <code>upload.array('fieldName', maxCount)</code>. The <code>maxCount</code> parameter limits how many files can be sent at once, which helps prevent abuse and server overload. After processing, Multer attaches an array of file objects to <code>req.files</code> instead of a single <code>req.file</code>. You can loop through this array to save records to a database, generate access URLs, or run validation checks.</p>
<p>If your form contains multiple different file fields (for example, <code>avatar</code> and <code>documents</code>), you can use <code>upload.fields()</code>. You pass an array of objects defining each field name and its maximum count. Multer then organizes the results into <code>req.files</code> as an object where each key holds its own array of files.</p>
<p>This structure keeps complex upload forms clean and prevents route handlers from becoming messy.</p>
<p>Uploading files is only half the process. Users also need to access them.</p>
<h2>Serving Uploaded Files</h2>
<p>To serve uploaded files, you can use Express’s built-in <code>express.static()</code> middleware. Point it to your upload directory, and Express will automatically serve files when users request the correct URL.</p>
<p>For example, if your files are saved in an <code>uploads/</code> folder, mounting <code>app.use('/uploads', express.static('uploads'))</code> allows users to access a file via <code>http://localhost:3000/uploads/filename.jpg</code>. The browser will render images, download documents, or play media depending on the file type.</p>
<p>In production, you should follow a few security best practices:</p>
<ul>
<li><p>Never execute or trust uploaded files blindly</p>
</li>
<li><p>Validate file types on both frontend and backend</p>
</li>
<li><p>Restrict upload sizes to prevent disk exhaustion</p>
</li>
<li><p>Consider moving to cloud storage like AWS S3, Cloudinary, or Firebase for better scalability, CDN delivery, and automatic backups</p>
</li>
</ul>
<p>Serving files statically works perfectly for learning and small projects, but cloud storage handles traffic spikes, security, and global delivery more efficiently as your app grows.</p>
<h2>Conclusion</h2>
<p>File uploads are a common requirement, but they require careful handling to stay secure, efficient, and scalable. Multer removes the complexity of parsing multipart data and gives you a clean, reliable way to manage uploads in Express. By configuring storage properly, handling single and multiple files correctly, and serving them safely, you can build robust upload features without reinventing the wheel.</p>
<p>Understanding this flow gives you a clear picture of how modern web apps manage user-generated content, how to protect your server from malformed requests, and how to scale your upload system as your application grows. Start with disk storage, add validation, and move to cloud providers when you are ready. The rest is just practice.</p>
]]></content:encoded></item><item><title><![CDATA[JWT Authentication in Node.js Explained Simply]]></title><description><![CDATA[If you’ve ever built or used a modern web application, you’ve encountered the login screen countless times. Behind that simple username and password field lies a critical security process: authenticat]]></description><link>https://blog.suprabhat.site/jwt-authentication-in-node-js-explained-simply</link><guid isPermaLink="true">https://blog.suprabhat.site/jwt-authentication-in-node-js-explained-simply</guid><category><![CDATA[JWT]]></category><category><![CDATA[authentication]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Express]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sun, 03 May 2026 16:21:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/0c102a7f-7aac-48e3-8e02-d12bb41ef98c.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’ve ever built or used a modern web application, you’ve encountered the login screen countless times. Behind that simple username and password field lies a critical security process: authentication. In today’s API-driven world, one of the most popular and scalable ways to handle this is using JWTs, or JSON Web Tokens. They’re lightweight, stateless, and integrate seamlessly with Node.js backends. In this guide, we’ll break down what authentication means, what a JWT actually is, how it’s structured, and how to implement a secure login flow in Node.js, all explained for beginners.</p>
<h2>What Authentication Means</h2>
<p>Authentication is the process of verifying a user’s identity. When someone submits their credentials, the system checks whether they are who they claim to be. It’s crucial to distinguish authentication from authorization: authentication answers <em>“Who are you?”</em> while authorization answers <em>“What are you allowed to do?”</em></p>
<p>Think of authentication as showing your ID at a building’s front desk. Authorization is the access badge that decides which floors you can visit once inside. Without reliable authentication, malicious actors could easily impersonate legitimate users. JWTs solve this by providing a secure, cryptographically verifiable way to confirm identity across multiple requests without storing session data on the server.</p>
<h2>What is a JWT?</h2>
<p>A JWT (pronounced “jot”) is a compact, URL-safe token that securely represents claims between two parties. Unlike traditional session-based authentication, which stores user state on the server or in a database, JWTs are <strong>stateless</strong>.</p>
<p>Here’s how it works: after a successful login, your server generates a JWT and sends it to the client. The client stores it and attaches it to every subsequent request. The server doesn’t need to query a session store; it simply verifies the token’s signature to trust the claims inside. This makes JWTs highly efficient for RESTful APIs, mobile apps, and microservice architectures where scaling and performance matter.</p>
<h2>Structure of a JWT</h2>
<p>A JWT isn’t a random string of characters. It’s composed of three distinct parts, separated by dots: <code>header.payload.signature</code>. Each part is Base64Url encoded, which is why tokens look like long, unreadable sequences.</p>
<h3>Header</h3>
<p>The header contains metadata about the token. It typically specifies the signing algorithm and the token type.</p>
<pre><code class="language-json">{
  "alg": "HS256",
  "typ": "JWT"
}
</code></pre>
<h3>Payload</h3>
<p>The payload holds the actual claims, statements about the user and token metadata. Common standard claims include <code>sub</code> (subject/user ID), <code>iat</code> (issued at), and <code>exp</code> (expiration time). You can also include custom data. For example:</p>
<pre><code class="language-json">{
  "sub": "user_101",
  "name": "Suprabhat", age: 23,
  "role": "member",
  "iat": 1715000000,
  "exp": 1715003600
}
</code></pre>
<p><strong>Important:</strong> Payloads are encoded, not encrypted. Anyone can decode them using online tools. Never store sensitive information like passwords, credit card numbers, or private keys in a JWT.</p>
<h3>Signature</h3>
<p>The signature is the security backbone of the token. It’s created by taking the encoded header and payload, combining them with a secret key known only to your server, and running them through the algorithm specified in the header (e.g., HMAC-SHA256). If an attacker modifies the header or payload, the signature will no longer match, and the server will immediately reject the token.</p>
<h2>The JWT Login Flow</h2>
<p>Let’s walk through how this works in practice using our example user: <code>name: "Suprabhat", age: 23,</code>.</p>
<ol>
<li><p><strong>Login Request:</strong> Suprabhat enters their email and password on the frontend and submits a <code>POST</code> request to your Node.js <code>/api/login</code> endpoint.</p>
</li>
<li><p><strong>Credential Verification:</strong> Your server queries the database, hashes the submitted password, and compares it with the stored hash.</p>
</li>
<li><p><strong>Token Generation:</strong> If the credentials match, the server generates a JWT. It includes a unique user identifier, sets an expiration time (e.g., 1 hour), and signs it with a secure secret key.</p>
</li>
<li><p><strong>Response Delivery:</strong> The server sends the JWT back to the client, usually in the JSON response body or as a secure HTTP-only cookie.</p>
</li>
<li><p><strong>Client Storage:</strong> The frontend securely stores the token (commonly in memory or <code>localStorage</code>, depending on your security model).</p>
</li>
</ol>
<p>From this point forward, Suprabhat won’t need to log in again until the token expires. The JWT acts as a temporary, cryptographically verified digital ID card.</p>
<h2>Sending Tokens with Requests</h2>
<p>Once the client holds the JWT, it must attach it to every request that requires authentication. The industry standard is using the <code>Authorization</code> HTTP header with the <code>Bearer</code> scheme:</p>
<pre><code class="language-shell">GET /api/dashboard
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEwMSJ9...
</code></pre>
<p>Modern frontend frameworks handle this automatically. For example, using Axios, you can set up a request interceptor that reads the stored token and attaches it before every API call.</p>
<p><strong>Security Tip:</strong> Never pass JWTs in URL query parameters. URLs are logged in browser history, server logs, and proxy caches, making tokens highly vulnerable to leakage.</p>
<h2>Protecting Routes in Node.js</h2>
<p>Now, let’s see how your Node.js server verifies incoming tokens. You’ll typically use the official <code>jsonwebtoken</code> package to build a reusable middleware function.</p>
<pre><code class="language-javascript">const jwt = require('jsonwebtoken');

const authenticateToken = (req, res, next) =&gt; {
  const authHeader = req.headers['authorization'];
  const token = authHeader &amp;&amp; authHeader.split(' ')[1]; // Extracts "Bearer &lt;token&gt;"

  if (!token) {
    return res.status(401).json({ error: 'Authentication required' });
  }

  jwt.verify(token, process.env.JWT_SECRET, (err, user) =&gt; {
    if (err) {
      return res.status(403).json({ error: 'Invalid or expired token' });
    }
    req.user = user; // Attach decoded payload to the request object
    next(); // Proceed to the actual route handler
  });
};

// Apply middleware to protected routes
app.get('/api/profile', authenticateToken, (req, res) =&gt; {
  res.json({ message: `Welcome, ${req.user.name}!` });
});
</code></pre>
<p>This middleware checks for the presence of a token, verifies its cryptographic signature, and ensures it hasn’t expired. If valid, it attaches the decoded payload to <code>req.user</code>, making user data available to your route handlers. If invalid, it short-circuits the request with a clear HTTP status code.</p>
<h2>Conclusion</h2>
<p>JWT authentication might sound intimidating at first, but it’s fundamentally just a secure, standardized way to pass verified user data between client and server. By understanding its three-part structure, mastering the login flow, and implementing clean verification middleware in Node.js, you can build scalable, stateless APIs with confidence.</p>
<p>Always follow security best practices: use strong, randomly generated secret keys, set reasonable token expiration times, implement token refresh strategies for longer sessions, and never expose sensitive data in the payload. With these foundations in place, you’re well-equipped to secure your next Node.js application like a pro.</p>
]]></content:encoded></item><item><title><![CDATA[Blocking vs Non-Blocking Code in Node.js]]></title><description><![CDATA[Across the Internet, every modern web application handles hundreds or thousands of requests at the same time. But behind the scenes, Node.js runs on a single thread. If one task takes too long, everyt]]></description><link>https://blog.suprabhat.site/blocking-vs-non-blocking-code-in-node-js</link><guid isPermaLink="true">https://blog.suprabhat.site/blocking-vs-non-blocking-code-in-node-js</guid><category><![CDATA[Node.js]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sat, 02 May 2026 05:44:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/0d8e4a18-d191-437e-b87f-8157164dfbb4.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Across the Internet, every modern web application handles hundreds or thousands of requests at the same time. But behind the scenes, Node.js runs on a single thread. If one task takes too long, everything else stops. This is where the difference between blocking and non-blocking code becomes critical. In this blog we will understand what is blocking and non-blocking code, how they affect the Event Loop, see practical examples with file and database operations, and how this connects to real Node.js applications.</p>
<p>First, let’s understand what is blocking code and why it matters.</p>
<h2>What is blocking code and why it matters</h2>
<p>Blocking code runs synchronously. This means the program stops and waits for an operation to finish before moving to the next line. If a task takes five seconds to complete, the entire JavaScript thread pauses for five seconds.</p>
<p>In Node.js, this is dangerous because there is only one main thread. When the thread is blocked, the Event Loop cannot pick up new requests, process timers, or handle any other callbacks. The server appears frozen to all users until the blocking task finishes.</p>
<p>Common examples of blocking code include:</p>
<ul>
<li><p><code>fs.readFileSync()</code> for file operations</p>
</li>
<li><p><code>crypto.pbkdf2Sync()</code> for password hashing</p>
</li>
<li><p>Heavy <code>for</code> or <code>while</code> loops with complex calculations</p>
</li>
<li><p>Synchronous database queries in older drivers</p>
</li>
</ul>
<p>While blocking code is simple to read and debug, it does not scale. A single slow file read or a complex math operation can delay hundreds of other requests waiting in line. Beginners often use blocking methods because they look straightforward, but in production servers, they become performance bottlenecks.</p>
<h2>What is non-blocking code and how it works</h2>
<p>Non-blocking code runs asynchronously. Instead of waiting for a task to finish, Node.js hands the operation to Libuv in the background and immediately continues executing the next lines of code.</p>
<p>When the background task completes, the result is placed in the Callback Queue. The Event Loop later picks it up and runs the callback or resolves the promise. This keeps the main thread free to handle other incoming requests.</p>
<p>Examples of non-blocking code include:</p>
<ul>
<li><p><code>fs.readFile()</code> with callbacks or promises</p>
</li>
<li><p><code>fetch()</code> or <code>axios</code> for HTTP requests</p>
</li>
<li><p>Database queries using <code>async/await</code></p>
</li>
<li><p><code>setTimeout()</code> and <code>setInterval()</code> for delayed execution</p>
</li>
</ul>
<p>Non-blocking code does not mean the task finishes faster. It means the server does not waste time waiting. It can serve other users while the background work completes. This is why Node.js excels at I/O-heavy applications like APIs, real-time chats, and streaming services.</p>
<p>A common point of confusion is <code>async/await</code>. It looks synchronous when you read it, but it is completely non-blocking. The <code>await</code> keyword pauses only the current function, not the entire Event Loop. Other requests continue processing normally.</p>
<h2>Step by step comparison with practical examples</h2>
<p>Let’s compare both approaches using a simple file read operation.</p>
<p><strong>Blocking version:</strong></p>
<pre><code class="language-javascript">const fs = require('fs');
const data = fs.readFileSync('users.json', 'utf8');
console.log('File read finished');
console.log(data);
</code></pre>
<p>In this code, the program stops at <code>readFileSync()</code>. It waits until the entire file is loaded into memory. Only then does it print the logs. If another user sends a request during this wait, the server ignores it until the file read completes.</p>
<p><strong>Non-blocking version:</strong></p>
<pre><code class="language-javascript">const fs = require('fs').promises;
fs.readFile('users.json', 'utf8')
  .then(data =&gt; console.log(data))
  .catch(err =&gt; console.error(err));
console.log('File read started');
</code></pre>
<p>Here, <code>readFile()</code> starts the operation and immediately moves to the next line. The console prints "File read started" right away. When the file finishes loading in the background, the <code>.then()</code> callback runs. The Event Loop stays free to process other tasks in the meantime.</p>
<p>The same principle applies to database calls, API requests, and network operations. Non-blocking code keeps the application responsive under load.</p>
<h2>How blocking and non-blocking code affect the Event Loop</h2>
<p>The Event Loop is designed to stay fast and continuous. It constantly checks the Call Stack, moves tasks from the Callback Queue, and runs them one by one.</p>
<p>When you use blocking code, you freeze the Call Stack. The Event Loop cannot move to the next phase. Timers delay, pending callbacks stack up, and new requests queue indefinitely. The poll phase stops waiting for I/O because the thread is busy running synchronous code. Even <code>setTimeout</code> callbacks will not fire until the blocking operation finishes.</p>
<p>When you use non-blocking code, the Event Loop flows smoothly. I/O tasks go to Libuv, the main thread stays empty, and the loop continues cycling through phases. Completed tasks enter the queue and get executed without interrupting other operations. The poll phase efficiently waits for I/O events and immediately processes them when ready.</p>
<p>This is why writing non-blocking code is not just a best practice in Node.js. It is a requirement for performance.</p>
<h2>Common mistakes beginners make</h2>
<p>Many developers new to Node.js accidentally block the Event Loop without realizing it. Here are the most frequent pitfalls:</p>
<ul>
<li><p><strong>Using sync methods in route handlers:</strong> <code>fs.readFileSync()</code> inside an Express route will freeze that route for every user.</p>
</li>
<li><p><strong>Heavy JSON parsing:</strong> <code>JSON.parse()</code> on a massive payload runs on the main thread and blocks other requests.</p>
</li>
<li><p><strong>Complex loops:</strong> Nested <code>for</code> loops with thousands of iterations consume CPU and stop the loop from checking the queue.</p>
</li>
<li><p><strong>Ignoring promise rejections:</strong> Unhandled promise rejections do not block the loop immediately, but they cause memory leaks and eventual crashes.</p>
</li>
</ul>
<p>To avoid these, always profile your code, use streaming for large files, and move CPU-heavy work outside the main thread.</p>
<h2>When to use blocking vs non-blocking code</h2>
<p>Choosing the right approach depends on your use case.</p>
<p><strong>Use non-blocking code for:</strong></p>
<ul>
<li><p>File reads and writes in web servers</p>
</li>
<li><p>Database queries and API calls</p>
</li>
<li><p>Network requests and WebSocket messages</p>
</li>
<li><p>Any I/O operation that involves waiting for external systems</p>
</li>
</ul>
<p><strong>Use blocking code only for:</strong></p>
<ul>
<li><p>Simple scripts or CLI tools where performance does not matter</p>
</li>
<li><p>Application startup tasks that must finish before the server begins listening</p>
</li>
<li><p>Configuration file reads that happen once during initialization</p>
</li>
</ul>
<p>If you must run heavy CPU tasks like image processing, video encoding, or complex data analysis, do not block the main thread. Instead, use Worker Threads or Child Processes. These run in separate threads and communicate with the main process without freezing the Event Loop.</p>
<h2>Connecting blocking vs non-blocking to real user requests</h2>
<p>When a user interacts with your application, the difference becomes obvious.</p>
<p>Let’s imagine a user named: "Suprabhat", age: 23, tries to log into a web application. The server needs to read his profile data from a JSON file and verify his password.</p>
<p><strong>If the server uses blocking code:</strong> Suprabhat clicks login. The server calls <code>readFileSync()</code> and <code>hashSync()</code>. The entire thread pauses. If another user tries to register at the same time, their request waits. Suprabhat’s page hangs until both operations finish. Under heavy traffic, the server times out and returns 503 errors.</p>
<p><strong>If the server uses non-blocking code:</strong> Suprabhat clicks login. The server hands the file read and password check to Libuv. The Event Loop continues handling other requests. When the background tasks finish, the results return to the queue. The Event Loop picks them up, formats the response, and sends it back. Suprabhat gets a fast response, and other users are not affected.</p>
<p>This shows how non-blocking code directly improves user experience and server stability.</p>
<h2>Conclusion</h2>
<p>Blocking code stops execution and waits. Non-blocking code continues running and handles results later. In a single-threaded environment like Node.js, this difference determines whether your application scales or crashes under load.</p>
<p>Always prefer non-blocking I/O for web servers. Use <code>async/await</code> or promises to keep code clean and readable. Reserve synchronous methods for startup scripts or local tools. For CPU-heavy work, move it to Worker Threads.</p>
<p>Understanding this flow gives a clear picture of how servers manage heavy traffic without freezing. Choosing the right execution model keeps the Event Loop free and ensures every request gets processed smoothly!</p>
]]></content:encoded></item><item><title><![CDATA[REST API Design Made Simple with Express.js]]></title><description><![CDATA[Across the Internet, every modern web application communicates through APIs. Frontend apps, mobile clients, and third-party services all depend on predictable endpoints to exchange data. But building ]]></description><link>https://blog.suprabhat.site/rest-api-design-made-simple-with-express-js</link><guid isPermaLink="true">https://blog.suprabhat.site/rest-api-design-made-simple-with-express-js</guid><category><![CDATA[REST API]]></category><category><![CDATA[Express]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sat, 02 May 2026 05:15:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/b7b0b49e-feda-47d7-a152-f98665d354ae.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Across the Internet, every modern web application communicates through APIs. Frontend apps, mobile clients, and third-party services all depend on predictable endpoints to exchange data. But building an API that is clean, scalable, and easy to maintain can feel overwhelming for beginners. In this blog we will understand what REST principles are and why they matter, how to map them to Express.js routes, see practical examples with proper status codes and JSON structure, and how this connects to real-world API design.</p>
<p>First, let’s understand what REST is and why it matters.</p>
<h2>What is REST and why it matters</h2>
<p>REST stands for Representational State Transfer. It is not a protocol or a framework. It is an architectural style that defines how clients and servers should communicate over HTTP. REST relies on a few core principles that keep APIs predictable and easy to work with.</p>
<p>Resources are the foundation. Every piece of data in your system is treated as a resource, identified by a URL. Instead of calling actions like <code>getUser</code> or <code>createOrder</code>, you work with resources like <code>/users</code> or <code>/orders</code>.</p>
<p>HTTP methods define the action. GET retrieves data, POST creates new records, PUT or PATCH updates existing ones, and DELETE removes them. This standardization means any developer can understand your API just by looking at the route and method.</p>
<p>Stateless communication ensures scalability. Each request contains all the information the server needs. The server does not store session state between requests, which makes horizontal scaling and caching much easier.</p>
<p>When you follow REST principles, your API becomes self-documenting, consistent, and ready for any frontend framework or mobile app.</p>
<h2>Mapping REST principles to Express.js routes</h2>
<p>Express.js is a minimal Node.js framework that makes routing straightforward. You can map REST concepts directly to Express route handlers.</p>
<pre><code class="language-javascript">const express = require('express');
const app = express();
app.use(express.json());

app.get('/users', (req, res) =&gt; {
  res.json({ message: 'Fetch all users' });
});

app.post('/users', (req, res) =&gt; {
  res.status(201).json({ message: 'User created' });
});

app.get('/users/:id', (req, res) =&gt; {
  res.json({ message: `Fetch user ${req.params.id}` });
});

app.put('/users/:id', (req, res) =&gt; {
  res.json({ message: `Update user ${req.params.id}` });
});

app.delete('/users/:id', (req, res) =&gt; {
  res.status(204).send();
});
</code></pre>
<p>This structure mirrors REST perfectly. URLs use plural nouns for collections. Route parameters like <code>:id</code> target specific resources. Each HTTP method triggers the correct operation. Express handles the routing logic while you focus on the business rules.</p>
<h2>Step by step API route design</h2>
<p>Designing a route goes beyond picking a URL. You need to handle request data, validate inputs, return proper status codes, and format responses consistently.</p>
<p><strong>Use clear URL naming</strong> Stick to nouns, not verbs. <code>/users</code> is better than <code>/getUsers</code>. Use nested routes for relationships like <code>/users/:userId/posts</code>.</p>
<p><strong>Handle request data properly</strong> POST and PUT requests send data in the request body. Express needs <code>express.json()</code> middleware to parse it. Always validate incoming data before processing it.</p>
<p><strong>Return correct HTTP status codes</strong> Status codes tell the client what happened. Use 200 for successful GET/PUT, 201 for successful POST, 204 for successful DELETE with no body, 400 for bad requests, 404 for missing resources, and 500 for server errors.</p>
<p><strong>Standardize JSON responses</strong> Keep your response structure consistent. Wrap data in a predictable format so frontend developers know exactly what to expect.</p>
<pre><code class="language-javascript">// Success response
{
  "success": true,
  "data": { "id": 1, "name": "Suprabhat" },
  "message": "User fetched successfully"
}

// Error response
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Email is required"
  }
}
</code></pre>
<p>This consistency reduces frontend bugs and makes API documentation easier to maintain.</p>
<h2>Best practices for clean API design</h2>
<p>REST is simple in theory, but real-world projects introduce complexity. Following these practices keeps your API maintainable as it grows.</p>
<ul>
<li><p><strong>Separate routes and controllers:</strong> Keep route definitions in one file and business logic in another. This makes testing and debugging easier.</p>
</li>
<li><p><strong>Use middleware for shared logic:</strong> Authentication, logging, and error handling should run as middleware instead of repeating code in every route.</p>
</li>
<li><p><strong>Handle errors gracefully:</strong> Never expose stack traces in production. Create a centralized error handler that catches unhandled exceptions and returns clean JSON responses.</p>
</li>
<li><p><strong>Version your API:</strong> Add <code>/api/v1/</code> to your base path. This allows you to introduce breaking changes later without disrupting existing clients.</p>
</li>
<li><p><strong>Avoid over-fetching:</strong> Let clients request only the fields they need using query parameters like <code>?fields=name,email</code>. This reduces payload size and improves performance.</p>
</li>
</ul>
<p>These practices transform a basic Express server into a production-ready API that scales smoothly.</p>
<h2>Connecting REST API design to real requests</h2>
<p>When a frontend application calls your API, the same routing and response flow happens behind the scenes.</p>
<p>Client → Sends GET /users/123 Express → Matches route and extracts params Controller → Queries database and formats data Middleware → Adds security headers and logs request Server → Returns standardized JSON response</p>
<p>Let’s imagine a user named: "Suprabhat", age: 23, opens a dashboard that fetches his profile data. The frontend sends a GET request to <code>/api/v1/users/123</code>. Express matches the route, the controller queries the database, and the response returns a clean JSON object with his name, age, and preferences. If Suprabhat updates his email, the frontend sends a PATCH request with only the changed field. The server validates the input, updates the record, and returns a 200 status with the new data. Every interaction follows the same predictable pattern, making the system reliable and easy to debug.</p>
<h2>Conclusion</h2>
<p>REST API design is about consistency, clarity, and leveraging HTTP standards. Express.js makes it straightforward to map resources to routes, handle requests cleanly, and return predictable responses. By following proper naming conventions, status codes, and response formatting, you build APIs that frontend teams and external services can integrate with ease.</p>
<p>Always keep routes modular, validate incoming data, and centralize error handling. Version your endpoints and avoid over-fetching to keep payloads lean. Understanding this flow gives a clear picture of how servers exchange data reliably while staying fast and maintainable.</p>
<p>Choosing the right structure from day one saves hours of refactoring later. With Express.js and REST principles, building scalable APIs becomes a simple, repeatable process!</p>
]]></content:encoded></item><item><title><![CDATA[The Node.js Event Loop Explained]]></title><description><![CDATA[Across the Internet, every modern web application handles hundreds or thousands of requests at the same time. But behind the scenes, Node.js runs on a single thread. How does it manage heavy workloads]]></description><link>https://blog.suprabhat.site/the-node-js-event-loop-explained</link><guid isPermaLink="true">https://blog.suprabhat.site/the-node-js-event-loop-explained</guid><category><![CDATA[Node.js]]></category><category><![CDATA[node]]></category><category><![CDATA[Event Loop]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Wed, 29 Apr 2026 07:06:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/7b44c8cb-3dfb-46b0-b3f6-54a5c7223afe.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Across the Internet, every modern web application handles hundreds or thousands of requests at the same time. But behind the scenes, Node.js runs on a single thread. How does it manage heavy workloads without freezing or slowing down? In this blog we will understand what is the Event Loop and why it exists, how it works step by step using its different phases, and how this connects to real Node.js applications.</p>
<p>First, let’s understand what is the Event Loop and why it exists.</p>
<h2>What is the Event Loop and why it exists</h2>
<p>Node.js is single-threaded. This means it can only execute one piece of JavaScript code at a time. If Node.js had to wait for every database query, file read, or API call to finish before moving to the next line, it would become extremely slow and unresponsive.</p>
<p>To solve this, Node.js uses the Event Loop. It acts like a smart traffic manager that constantly checks if background tasks are finished. When a task completes, the Event Loop picks it up and hands it back to the main thread. This makes Node.js non-blocking and highly efficient for I/O-heavy operations.</p>
<p>Without the Event Loop, we would need multi-threading for every request, which consumes more memory and is harder to manage. The Event Loop gives us the speed of async programming with the simplicity of a single thread.</p>
<h2>How the Event Loop works step by step</h2>
<p>Before understanding the phases, we need to know the main components that work together behind the scenes.</p>
<p>The Call Stack runs JavaScript code line by line. It is where all your synchronous functions execute. When you call a function, it goes on top of the stack. When it returns, it gets removed.</p>
<p>When an async task like reading a file or making an HTTP request happens, it is handed off to Libuv. Libuv is a C library that handles system-level operations in the background. It manages thread pools, network sockets, and file system operations.</p>
<p>Once the background task finishes, the result is placed in the Callback Queue.</p>
<p>The Event Loop constantly checks one simple question: Is the Call Stack empty?</p>
<p>If yes, it takes the first task from the Callback Queue and pushes it onto the Call Stack. Then the main thread executes it. This cycle repeats endlessly, making Node.js fast and responsive.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/d0bf9a4b-eaa7-4462-b9d4-79edc4c8fd2e.png" alt="Event Loop Architecture" style="display:block;margin:0 auto" />

<p>Now let’s understand how the Event Loop moves through its different phases.</p>
<h2>Understanding the different phases of the Event Loop</h2>
<p>The Event Loop does not just pick tasks randomly. It moves through specific phases in a strict order. Each phase has its own purpose and runs callbacks accordingly.</p>
<p><strong>Timers Phase</strong> This phase runs callbacks scheduled by <code>setTimeout</code> and <code>setInterval</code>. If you set a timeout for 2000 milliseconds, the Event Loop checks if enough time has passed and executes the callback in this phase.</p>
<p><strong>Pending Callbacks Phase</strong> This phase handles certain system operations that could not run in the previous phase. It mainly deals with TCP error messages or network events that need immediate attention.</p>
<p><strong>Poll Phase</strong> This is the most important phase. It waits for new I/O events to complete, like reading a file, receiving a database response, or handling incoming requests. If the Callback Queue is empty, the Event Loop will actually pause here until new tasks arrive. This prevents the loop from wasting CPU cycles.</p>
<p><strong>Check Phase</strong> This phase runs <code>setImmediate()</code> callbacks. It is used when you want to execute code right after the poll phase completes, without waiting for timers.</p>
<p><strong>Close Callbacks Phase</strong> This phase handles cleanup operations. It runs callbacks for closed connections, like <code>socket.on('close')</code> or file stream closures.</p>
<p>After the close phase, the loop checks if there are any active handles or pending requests. If yes, it starts over from the timers phase. If not, the Node.js process exits gracefully.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/fb181152-7700-4c71-81fa-c7bd4854e4f3.png" alt="Event Loop Architecture Phases Flow" style="display:block;margin:0 auto" />

<h2>Understanding process.nextTick and setImmediate</h2>
<p>Developers often confuse <code>process.nextTick()</code> and <code>setImmediate()</code>. They look similar but work differently.</p>
<p><code>process.nextTick()</code> is not part of the Event Loop phases. It runs immediately after the current operation finishes, before the loop moves to the next phase.</p>
<p><code>setImmediate()</code> runs inside the check phase of the Event Loop.</p>
<p>This means <code>process.nextTick()</code> has higher priority. If you mix both in your code, <code>nextTick</code> callbacks will always run first. This is useful for breaking up long-running tasks or deferring work to the next iteration without leaving the current call context.</p>
<h2>How to avoid blocking the Event Loop</h2>
<p>Since Node.js runs on a single thread, blocking the Event Loop can freeze your entire application. Heavy synchronous operations like large JSON parsing, complex math calculations, or synchronous file reads will stop the loop from processing other requests.</p>
<p>When to use what:</p>
<ul>
<li><p>Use async/await or Promises for database calls, file operations, and API requests.</p>
</li>
<li><p>Avoid <code>sync</code> methods like <code>fs.readFileSync</code> in production servers.</p>
</li>
<li><p>Use worker threads or child processes for CPU-heavy tasks like image processing or data encryption.</p>
</li>
</ul>
<p>This keeps the Event Loop free to handle incoming traffic while heavy work runs in parallel.</p>
<h2>Connecting the Event Loop to real Node.js requests</h2>
<p>When a user sends a request to your Node.js server, the same Event Loop process happens behind the scenes.</p>
<p>Browser → Sends HTTP request Server → Receives request and places it in the queue Event Loop → Picks up the request and passes I/O work to Libuv Libuv → Handles database query or file read in background Poll Phase → Waits for the database to respond Check Phase → Executes response formatting Server → Sends data back to the browser</p>
<p>Let’s imagine a user named: "Suprabhat", age: 23, logs into a web app. When he clicks login, the server does not stop to wait for the database. It hands the query to Libuv, continues handling other requests, and only returns to format Suprabhat’s profile data once the database replies. This keeps the app fast even under heavy traffic.</p>
<p>So every web request depends on the Event Loop before any response is sent back.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/d234c779-2c8d-46ca-97f3-18848596c3f4.png" alt="Real Request Flow Through the Event Loop" style="display:block;margin:0 auto" />

<h2>Conclusion</h2>
<p>The Event Loop is the hidden engine that makes Node.js fast and scalable. It handles async work smartly by moving heavy tasks to background threads and checking back only when needed. Understanding this flow gives a clear picture of how servers manage heavy traffic without blocking or crashing.</p>
<p>Choosing the right async method depends on what you need. If you need something to run immediately after the current task, use <code>process.nextTick()</code>. If you want to run code in the next loop iteration, use <code>setImmediate()</code>. Understanding these phases helps you see how the "invisible" parts of Node.js work every time your server handles a request!</p>
]]></content:encoded></item><item><title><![CDATA[Setting Up Your First Node.js Application Step-by-Step]]></title><description><![CDATA[Across the Internet, every modern web application, API, or backend service you interact with often runs on JavaScript outside the browser. But browsers are not the only place JavaScript lives. To run ]]></description><link>https://blog.suprabhat.site/setting-up-your-first-node-js-application-step-by-step</link><guid isPermaLink="true">https://blog.suprabhat.site/setting-up-your-first-node-js-application-step-by-step</guid><category><![CDATA[Node.js]]></category><category><![CDATA[node]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[server]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Tue, 28 Apr 2026 13:52:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/1e287d76-79ac-4a85-b979-e26b5987f5cf.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Across the Internet, every modern web application, API, or backend service you interact with often runs on JavaScript outside the browser. But browsers are not the only place JavaScript lives. To run JavaScript on your computer or server, we use a runtime called Node.js.</p>
<p>In this blog, we will understand how to install Node.js, verify the installation using the terminal, explore the Node REPL, create your first JavaScript file, run it using the node command, and finally build a simple Hello World server. By the end, you will have a fully working Node.js setup and your first backend application running locally.</p>
<p>First, let’s understand how to install Node.js.</p>
<h2>Installing Node.js</h2>
<p>Node.js is an open-source JavaScript runtime that allows you to execute JavaScript code outside the browser. It is built on Chrome’s V8 engine and is widely used for building fast, scalable network applications.</p>
<p>To install Node.js, visit the official website at <code>nodejs.org</code>. You will see two versions available for download: LTS (Long Term Support) and Current. For beginners and production environments, always choose the LTS version. It is stable, well-tested, and receives long-term security updates.</p>
<p>Download the installer for your operating system (Windows, macOS, or Linux) and follow the setup wizard. Keep the default options selected, especially the one that adds Node.js to your system PATH. This step ensures you can run <code>node</code> and <code>npm</code> commands from any terminal window without configuring environment variables manually.</p>
<p>Once the installation finishes, you are ready to verify it.</p>
<h2>Checking installation using terminal</h2>
<p>After installing Node.js, the next step is to confirm that it was installed correctly. Open your terminal (Command Prompt or PowerShell on Windows, Terminal on macOS/Linux) and type the following command:</p>
<pre><code class="language-shell">node -v
</code></pre>
<p>This command asks: What version of Node.js is currently installed on my system?</p>
<p>If the installation was successful, you will see a version number like <code>v24.12.0</code> The exact number may vary depending on when you install it.</p>
<pre><code class="language-shell">v24.12.0
</code></pre>
<p>Node.js also comes bundled with npm (Node Package Manager), which helps you install third-party libraries, manage project dependencies, and run scripts. To check npm, run:</p>
<pre><code class="language-shell">npm -v
</code></pre>
<p>You should see a version number like <code>11.6.2</code> If both commands return versions without errors, your setup is complete and ready for development.</p>
<p>Now let’s explore an interactive feature of Node.js.</p>
<h2>Understanding Node REPL</h2>
<p>REPL stands for Read-Eval-Print Loop. It is an interactive command-line environment where you can type JavaScript code, press Enter, and see the result immediately.</p>
<p>To start the REPL, simply type:</p>
<pre><code class="language-shell">node
</code></pre>
<p>You will notice the terminal prompt changes to <code>&gt;</code>. This means you are now inside the Node.js environment.</p>
<p>Try typing simple JavaScript expressions:</p>
<pre><code class="language-javascript">&gt; 2 + 3
5
&gt; console.log("Hello, Suprabhat")
Hello, Suprabhat
undefined
</code></pre>
<p>The REPL reads your input, evaluates it, prints the output, and loops back for the next command. It is extremely useful for testing small code snippets, checking syntax, or experimenting with JavaScript features without creating a file.</p>
<p>To exit the REPL, press <code>Ctrl + C</code> twice or type <code>.exit</code> and press Enter.</p>
<p>While REPL is great for quick tests, real applications are written in files. Let’s create one.</p>
<h2>Creating first JS file</h2>
<p>Open your favorite code editor (VS Code is highly recommended for beginners). Create a new folder for your project, for example <code>my-first-node-app</code>. Inside this folder, create a new file named <code>app.js</code>.</p>
<p>Now, write a simple JavaScript statement inside the file:</p>
<pre><code class="language-javascript">console.log("Welcome to Node.js, Suprabhat!");
</code></pre>
<p>Save the file. Unlike browser JavaScript, Node.js does not need an HTML file or a browser window to run. It executes JavaScript directly from your terminal.</p>
<p>Before running it, make sure your terminal is pointing to the correct folder. Use the <code>cd</code> command to navigate:</p>
<pre><code class="language-shell">cd path/to/my-first-node-app
</code></pre>
<p>Now you are ready to execute the script.</p>
<h2>Running script using node command</h2>
<p>To run your JavaScript file, use the node command followed by the filename:</p>
<pre><code class="language-shell">node app.js
</code></pre>
<p>Behind the scenes, Node.js reads the file, compiles the JavaScript using the V8 engine, and executes it line by line.</p>
<p>You should see the following output in your terminal:</p>
<pre><code class="language-shell">Welcome to Node.js, Suprabhat!
</code></pre>
<p>If you make changes to <code>app.js</code>, you will need to run the <code>node app.js</code> command again to see the updated output. Node.js does not auto-reload by default, which keeps it lightweight and predictable.</p>
<p>This simple workflow, write, save, run, is the foundation of every Node.js application. Now let’s take it one step further and build a real server.</p>
<h2>Writing Hello World server</h2>
<p>So far, we have run simple scripts. But Node.js shines when it comes to building network servers. Let’s create a basic HTTP server that responds with “Hello World” when you visit it in a browser.</p>
<p>Replace the content of <code>app.js</code> with the following code:</p>
<pre><code class="language-javascript">const http = require('http');

const server = http.createServer((req, res) =&gt; {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello World from Node.js!\n');
});

const PORT = 3000;
server.listen(PORT, () =&gt; {
  console.log(`Server is running at http://localhost:${PORT}`);
});
</code></pre>
<p>Let’s break down what this code does:</p>
<ul>
<li><p><code>require('http')</code> loads Node.js’s built-in HTTP module, which handles web requests.</p>
</li>
<li><p><code>http.createServer()</code> creates a server that listens for incoming connections.</p>
</li>
<li><p>The callback function receives <code>req</code> (request) and <code>res</code> (response). Every time someone visits the server, this function runs.</p>
</li>
<li><p><code>res.writeHead(200, ...)</code> sets a successful HTTP status code and tells the browser to expect plain text.</p>
</li>
<li><p><code>res.end()</code> sends the final response and closes the connection.</p>
</li>
<li><p><code>server.listen(3000)</code> starts the server on port 3000 and prints a confirmation message.</p>
</li>
</ul>
<p>Save the file and run it again:</p>
<pre><code class="language-shell">node app.js
</code></pre>
<p>You will see:</p>
<pre><code class="language-shell">Server is running at http://localhost:3000
</code></pre>
<p>Open your browser and visit <code>http://localhost:3000</code>. You should see “Hello World from Node.js!” displayed on the page.</p>
<p>To stop the server, press <code>Ctrl + C</code> in the terminal.</p>
<h2>Connecting your local server to real web requests</h2>
<p>When you visit <code>http://localhost:3000</code> in your browser, the same networking process happens that powers real websites. Your browser sends an HTTP request to your local machine. Node.js receives it, processes it through the server callback, and sends back the response over a TCP connection. Because TCP guarantees delivery and order, your browser receives the exact text you defined in <code>res.end()</code>.</p>
<p>This is the exact foundation that scales into real-world APIs, authentication systems, and full-stack applications. Every production Node.js server starts with this same pattern: listen on a port, handle requests, and send responses.</p>
<h2>Conclusion</h2>
<p>Node.js makes it incredibly simple to run JavaScript outside the browser and build fast, scalable server applications. From installing the runtime and verifying it in the terminal, to experimenting in the REPL, running your first script, and launching a working HTTP server, you have now completed the essential first steps of Node.js development.</p>
<p>Understanding this workflow gives you a clear picture of how backend applications start, how servers listen for requests, and how JavaScript powers both the frontend and the backend. In the next steps, you can explore npm packages, routing, Express.js, and connecting to databases.</p>
<p>Every large-scale Node.js application begins exactly like this, one file, one command, and one running server.</p>
]]></content:encoded></item><item><title><![CDATA[Creating Routes and Handling Requests with Express]]></title><description><![CDATA[Across the web, every application you interact with relies on servers receiving requests and sending back responses. But writing raw Node.js servers can feel repetitive, verbose, and difficult to mana]]></description><link>https://blog.suprabhat.site/creating-routes-and-handling-requests-with-express</link><guid isPermaLink="true">https://blog.suprabhat.site/creating-routes-and-handling-requests-with-express</guid><category><![CDATA[Express]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Tue, 28 Apr 2026 06:41:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/54a3eecc-0f3a-46a3-975f-f0af6b0ef71b.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Across the web, every application you interact with relies on servers receiving requests and sending back responses. But writing raw Node.js servers can feel repetitive, verbose, and difficult to manage. To make this easier, developers use a framework called Express.js.</p>
<p>In this blog, we will understand what Express.js is, why it simplifies Node.js development, how to create your first Express server, how to handle GET and POST requests, how to send responses, and how this connects to real browser and API calls.</p>
<p>First, let’s understand what Express.js is and why it exists.</p>
<h2>What Express.js is</h2>
<p>Express.js is a lightweight, fast, and flexible web framework built on top of Node.js. Think of it as a toolkit that gives you ready-made methods to handle routes, parse requests, and format responses. Instead of writing long, manual code to check URLs, handle HTTP methods, or set headers, Express gives you simple functions like <code>app.get()</code> and <code>app.post()</code>.</p>
<p>Express does not replace Node.js. It simply wraps around it and removes the boilerplate. It is unopinionated, meaning it does not force you into a specific project structure or database. You decide how to build your application, and Express provides the routing and middleware foundation to make it work smoothly.</p>
<h2>Why Express simplifies Node.js development</h2>
<p>When you use raw Node.js to create a server, you have to manually parse request URLs, check HTTP methods, handle query strings, read request bodies, and set response headers. This takes a lot of repetitive code and is prone to errors.</p>
<p>Express removes that friction. It provides:</p>
<ul>
<li><p>Clean, readable routing (<code>/home</code>, <code>/api/users</code>, <code>/login</code>, etc.)</p>
</li>
<li><p>Built-in middleware support for parsing JSON, handling cookies, and logging requests</p>
</li>
<li><p>Simple syntax for handling different HTTP methods</p>
</li>
<li><p>Easy error handling and response formatting</p>
</li>
<li><p>Seamless integration with template engines and static files</p>
</li>
</ul>
<p>Because of this, developers can focus on building features instead of managing low-level server logic. Express is the bridge between raw Node.js and production-ready web applications.</p>
<h2>Creating your first Express server</h2>
<p>Let’s start by setting up a basic Express server. First, make sure you have Node.js installed. Then, create a new folder, open your terminal, and run:</p>
<pre><code class="language-shell">npm init -y
npm install express
</code></pre>
<p>Now, create a file called <code>index.js</code> and add the following code:</p>
<pre><code class="language-javascript">const express = require('express');
const app = express();
const PORT = 3000;

app.listen(PORT, () =&gt; {
  console.log(`Server is running on http://localhost:${PORT}`);
});
</code></pre>
<p>This code does three simple things:</p>
<ul>
<li><p>Imports the Express module</p>
</li>
<li><p>Creates an application instance</p>
</li>
<li><p>Starts listening on port 3000</p>
</li>
</ul>
<p>When you run <code>node index.js</code>, your server is live. But right now, it does not respond to any requests. If you visit <code>http://localhost:3000</code> in your browser, you will see a loading state or a "Cannot GET /" error. Let’s fix that by adding routes.</p>
<h2>Handling GET requests</h2>
<p>GET requests are used when a client wants to retrieve data from the server. In Express, handling a GET request is straightforward. Add this to your <code>index.js</code> file:</p>
<pre><code class="language-javascript">app.get('/', (req, res) =&gt; {
  res.send('Welcome to the home page!');
});

app.get('/user', (req, res) =&gt; {
  res.send('User profile page');
});
</code></pre>
<p>Here’s what happens behind the scenes:</p>
<ul>
<li><p><code>app.get()</code> tells Express to listen for GET requests on a specific path</p>
</li>
<li><p>The first argument is the route (<code>/</code> or <code>/user</code>)</p>
</li>
<li><p>The second argument is a callback function with <code>req</code> (request) and <code>res</code> (response)</p>
</li>
<li><p>When you visit the route in your browser, Express matches the path and sends back the response</p>
</li>
</ul>
<p>GET requests are safe and idempotent. They should only fetch data, not modify anything on the server. Browsers also cache GET requests, which makes them fast for repeated visits.</p>
<h2>Handling POST requests</h2>
<p>POST requests are used when a client wants to send data to the server, like submitting a form, creating a new account, or uploading information. Unlike GET, POST requests carry a body. To read that body, Express needs a little help. Add this line before your routes:</p>
<pre><code class="language-javascript">app.use(express.json());
</code></pre>
<p>Now, create a POST route:</p>
<pre><code class="language-javascript">app.post('/user', (req, res) =&gt; {
  const userData = req.body;
  console.log('Received data:', userData);
  res.send('User created successfully');
});
</code></pre>
<p>How this works:</p>
<ul>
<li><p><code>express.json()</code> is middleware that parses incoming JSON data and attaches it to <code>req.body</code></p>
</li>
<li><p><code>req.body</code> contains the data sent by the client</p>
</li>
<li><p>The server logs the data and sends a confirmation response</p>
</li>
</ul>
<p>You can test this using tools like Postman or curl:</p>
<pre><code class="language-bash">curl -X POST http://localhost:3000/user -H "Content-Type: application/json" -d '{"name": "Suprabhat", "age": 23}'
</code></pre>
<p>POST requests are meant for creating or updating resources. They are not cached by browsers and can carry large payloads. Without the JSON middleware, <code>req.body</code> would be undefined, and your server would not be able to read the incoming data.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/ea598ca1-e66c-4d76-8848-dce0ef267fee.png" alt="GET vs POST request handling in Express" style="display:block;margin:0 auto" />

<h2>Sending responses</h2>
<p>Express gives you multiple ways to send responses back to the client. The method you choose depends on what kind of data you are returning and how the frontend expects to receive it.</p>
<p>The most common response methods are:</p>
<ul>
<li><p><code>res.send()</code>: Sends plain text, HTML, or buffers</p>
</li>
<li><p><code>res.json()</code>: Sends JSON data and automatically sets the correct <code>Content-Type</code> header</p>
</li>
<li><p><code>res.status()</code>: Sets HTTP status codes before sending a response</p>
</li>
<li><p><code>res.sendFile()</code>: Sends static files like images, PDFs, or documents</p>
</li>
</ul>
<p>Here’s a practical example combining status codes and JSON:</p>
<pre><code class="language-javascript">app.get('/api/info', (req, res) =&gt; {
  res.status(200).json({
    message: 'Success',
    data: { name: 'Suprabhat', age: 23, role: 'Developer' }
  });
});
</code></pre>
<p>Why response methods matter:</p>
<ul>
<li><p>They tell the client what happened (success, error, not found, unauthorized)</p>
</li>
<li><p>They format data correctly so the frontend or API consumer can read it</p>
</li>
<li><p>They control headers, status codes, and content types</p>
</li>
<li><p>They prevent broken connections and timeout errors</p>
</li>
</ul>
<p>Without proper responses, the client would not know if a request succeeded or failed. Status codes like <code>200</code> (OK), <code>201</code> (Created), <code>400</code> (Bad Request), and <code>404</code> (Not Found) are the universal language of web communication.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/735d2d6b-b4fb-46b8-b642-e5120f6eda58.png" alt="Express request response flow" style="display:block;margin:0 auto" />

<h2>Connecting Express routes to real browser and API requests</h2>
<p>When you type a URL in your browser, click a button in a web app, or call an API from a frontend framework, the same routing process happens.</p>
<p>Browser/API → Sends HTTP request → Express matches route → Runs callback → Sends response → Client receives data</p>
<p>Every web interaction depends on this request-response cycle. Express simply makes it predictable, readable, and easy to manage. Whether you are building a simple portfolio site, a REST API, or a full-stack application, routing is the backbone that connects users to your server logic.</p>
<h2>Conclusion</h2>
<p>Express.js is the missing piece that turns raw Node.js into a powerful, developer-friendly web framework. By simplifying routing, handling GET and POST requests cleanly, and providing flexible response methods, Express lets you build servers faster and with less code.</p>
<p>Understanding how routes work gives you a clear picture of how web applications communicate, how data flows between clients and servers, and how modern APIs are structured. Once you master these basics, you are ready to add middleware, connect databases, handle authentication, and build production-ready applications.</p>
]]></content:encoded></item><item><title><![CDATA[Why Node.js is Perfect for Building Fast Web Applications]]></title><description><![CDATA[If you’ve ever wondered how modern web applications handle thousands of simultaneous users without crashing or slowing down, you’ve likely stumbled upon Node.js. Originally released in 2009, Node.js t]]></description><link>https://blog.suprabhat.site/why-node-js-is-perfect-for-building-fast-web-applications</link><guid isPermaLink="true">https://blog.suprabhat.site/why-node-js-is-perfect-for-building-fast-web-applications</guid><category><![CDATA[Node.js]]></category><category><![CDATA[node]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Tue, 28 Apr 2026 06:19:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/97476c81-5505-461b-ba1c-724bb4bf5acf.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’ve ever wondered how modern web applications handle thousands of simultaneous users without crashing or slowing down, you’ve likely stumbled upon Node.js. Originally released in 2009, Node.js transformed JavaScript from a browser-only language into a powerful server-side runtime. But what truly sets it apart isn’t just its language, it’s its architecture.</p>
<p>In this guide, we’ll break down exactly what makes Node.js fast, demystify concepts like non-blocking I/O, event-driven architecture, and the single-threaded model, explore where Node.js shines in production, and look at real-world companies that trust it to power their platforms. Whether you’re a beginner or transitioning from another backend technology, this post will give you a clear, practical understanding of how Node.js works under the hood.</p>
<h2>What Makes Node.js Fast?</h2>
<p>When developers say “Node.js is fast,” they rarely mean raw computational speed. Languages like C++ or Rust will always outperform JavaScript in CPU-heavy tasks. Node.js’s speed comes from <strong>how it handles concurrency and I/O operations</strong>.</p>
<p>Traditional server models (like Apache or early Java servers) often use a multi-threaded approach: each incoming request gets its own thread. While this works for low traffic, threads consume memory and CPU. Under heavy load, thread creation and context switching become bottlenecks.</p>
<p>Node.js takes a completely different approach. Instead of spawning threads for every request, it uses a <strong>single-threaded, event-driven, non-blocking I/O model</strong>. This allows it to handle tens of thousands of concurrent connections with minimal overhead. Let’s unpack each of these pillars.</p>
<h2>The Single-Threaded Model Explained</h2>
<p>At first glance, “single-threaded” sounds like a limitation. How can one thread possibly handle multiple users at once?</p>
<p>In Node.js, <strong>JavaScript execution runs on a single main thread</strong>. This means your code executes line by line, without parallel JS execution. But here’s the catch: Node.js doesn’t use that thread to wait for slow operations like database queries, file reads, or network requests.</p>
<p>Think of it like a skilled receptionist at a busy clinic. Instead of personally performing every medical test (which would take hours), the receptionist logs requests, hands them off to specialists, and continues checking in new patients. When a test is complete, the specialist notifies the receptionist, who then delivers the results.</p>
<p>Under the hood, Node.js uses the <strong>V8 JavaScript engine</strong> (the same one powering Chrome) to compile JavaScript into highly optimized machine code. The single thread acts as an orchestrator, not a worker. Heavy lifting is delegated to the system via a C++ library called <strong>libuv</strong>, which manages a background thread pool specifically for I/O tasks.</p>
<h2>Non-Blocking I/O: The Secret Sauce</h2>
<p>I/O (Input/Output) refers to any operation that interacts with external resources: reading files, querying databases, making HTTP requests, or streaming data. These operations are inherently slow compared to CPU instructions.</p>
<p>In a <strong>blocking</strong> model, the thread pauses and waits until the I/O operation finishes. Nothing else can happen during that wait time. In a <strong>non-blocking</strong> model, Node.js initiates the I/O task, immediately moves on to the next line of code, and registers a callback to handle the result later.</p>
<p>Here’s a simplified example:</p>
<pre><code class="language-javascript">// Non-blocking database fetch
fetchUserFromDB((err, user) =&gt; {
  if (err) return console.error(err);
  console.log(user); // e.g., { name: "Suprabhat", age: 23, }
});

console.log("This runs immediately, without waiting for the DB!");
</code></pre>
<p>Notice how the second <code>console.log</code> executes right away. Node.js doesn’t sit idle while the database responds. It continues processing other requests, and when the database returns the data, the callback fires. This non-blocking behavior is what allows Node.js to maintain high throughput under heavy I/O load.</p>
<h2>Event-Driven Architecture: How Node.js Stays Responsive</h2>
<p>Non-blocking I/O is powerful, but it needs a system to track and manage all those pending operations. That’s where the <strong>event-driven architecture</strong> and the <strong>Event Loop</strong> come in.</p>
<p>The Event Loop is a continuously running mechanism that checks for completed asynchronous tasks and executes their associated callbacks. It operates in phases:</p>
<ol>
<li><p><strong>Timers</strong>: Executes <code>setTimeout</code> and <code>setInterval</code> callbacks.</p>
</li>
<li><p><strong>Pending Callbacks</strong>: Handles I/O callbacks deferred from previous loops.</p>
</li>
<li><p><strong>Poll</strong>: Retrieves new I/O events and executes their callbacks.</p>
</li>
<li><p><strong>Check</strong>: Runs <code>setImmediate</code> callbacks.</p>
</li>
<li><p><strong>Close</strong>: Handles cleanup callbacks (like closing sockets).</p>
</li>
</ol>
<p>Returning to our clinic analogy: the Event Loop is the receptionist’s clipboard. It constantly checks which test results are ready, matches them to the correct patient, and delivers them in order. Because the loop never blocks, Node.js stays responsive even when juggling thousands of pending requests.</p>
<p><strong>Important caveat:</strong> The Event Loop can be blocked by CPU-intensive JavaScript code (like complex loops or heavy data processing). If your main thread is stuck calculating, it can’t check the clipboard. That’s why Node.js is optimized for I/O-bound workloads, not CPU-bound ones.</p>
<h2>Where Node.js Performs Best</h2>
<p>Understanding Node.js’s architecture makes it easy to identify its ideal use cases:</p>
<p>✅ <strong>Real-Time Applications</strong>: Chat apps, live collaboration tools, and multiplayer games benefit from Node’s low-latency, bidirectional communication (often paired with WebSockets).<br />✅ <strong>APIs &amp; Microservices</strong>: Lightweight, fast, and JSON-native, Node.js is perfect for building RESTful or GraphQL APIs that handle high request volumes.<br />✅ <strong>Streaming Applications</strong>: Video/audio streaming, file uploads, and data pipelines work smoothly because Node processes data in chunks without buffering everything in memory.<br />✅ <strong>Single Page Applications (SPAs)</strong>: Serving assets and handling routing for React, Vue, or Angular frontends aligns perfectly with Node’s event-driven model.<br />✅ <strong>High-Concurrency, I/O-Heavy Workloads</strong>: Dashboards, notification systems, and proxy servers thrive under Node’s non-blocking architecture.</p>
<p>⛔ <strong>Where to Avoid Node.js</strong>: CPU-intensive tasks like video encoding, machine learning model training, or complex mathematical simulations. For these, consider offloading to worker threads, external services, or languages better suited for parallel computation.</p>
<h2>Real-World Companies Using Node.js</h2>
<p>Node.js isn’t just a developer favorite, it’s battle-tested at scale. Here’s how industry leaders leverage it:</p>
<p>🔹 <strong>Netflix</strong>: Migrated to Node.js to unify their frontend and backend stack, reducing startup time by 70% and enabling faster A/B testing.<br />🔹 <strong>PayPal</strong>: Replaced Java with Node.js for their web layer, cutting response times in half and doubling requests per second with fewer servers.<br />🔹 <strong>LinkedIn</strong>: Switched their mobile backend to Node.js, reducing server count from 30 to 3 while improving performance and developer velocity.<br />🔹 <strong>Uber</strong>: Uses Node.js for its massive real-time dispatch system, handling millions of concurrent connections with minimal latency.<br />🔹 <strong>Walmart</strong>: Adopted Node.js to handle Black Friday traffic spikes, successfully managing over 500 million page views without downtime.<br />🔹 <strong>NASA</strong>: Utilizes Node.js for data-intensive applications and internal tooling, proving its reliability even in mission-critical environments.</p>
<p>These companies didn’t choose Node.js for raw speed, they chose it for <strong>scalability, developer efficiency, and exceptional handling of concurrent I/O operations</strong>.</p>
<h2>Conclusion</h2>
<p>Node.js isn’t fast because it computes faster. It’s fast because it <strong>waits smarter</strong>. By combining a single-threaded JavaScript execution model, non-blocking I/O, and an event-driven architecture, Node.js eliminates the traditional bottlenecks of server-side programming. It thrives in environments where concurrency, real-time communication, and I/O efficiency matter more than heavy number crunching.</p>
<p>As you begin your Node.js journey, remember: architecture dictates performance. Use it for APIs, real-time apps, and microservices. Offload CPU-heavy tasks. Embrace asynchronous patterns. And most importantly, let the Event Loop do what it does best—keep your application responsive, scalable, and efficient.</p>
<p>Ready to build your first non-blocking server? Start small, experiment with callbacks and promises, and watch how Node.js handles concurrency with elegance. The modern web runs on event-driven systems, and now you understand exactly why.</p>
]]></content:encoded></item><item><title><![CDATA[Storing Uploaded Files and Serving Them in Express]]></title><description><![CDATA[Every time a user uploads a profile picture, shares a document, or attaches a resume, a hidden pipeline kicks in behind the scenes. But have you ever wondered where those files actually land? How does]]></description><link>https://blog.suprabhat.site/storing-uploaded-files-and-serving-them-in-express</link><guid isPermaLink="true">https://blog.suprabhat.site/storing-uploaded-files-and-serving-them-in-express</guid><category><![CDATA[multer]]></category><category><![CDATA[Express]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Tue, 28 Apr 2026 06:07:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/ed22ec5d-4ad4-4cfe-a997-7898a03e50f1.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every time a user uploads a profile picture, shares a document, or attaches a resume, a hidden pipeline kicks in behind the scenes. But have you ever wondered where those files actually land? How does your server store them, serve them back to the browser, and keep malicious uploads from breaking your application?</p>
<p>In this guide, we’ll walk through the complete lifecycle of file uploads in web applications. We’ll explore where files are stored, compare local vs. external storage, learn how to serve them using Express, access them via URLs, and cover essential security practices. By the end, you’ll have a clear, production-aware understanding of how modern apps handle user uploads safely and efficiently.</p>
<h2>Where Uploaded Files Are Stored</h2>
<p>When a user submits a file through a web form, it doesn’t instantly appear in a permanent folder. Instead, the server receives the file as a continuous stream of bytes. In Node.js environments, middleware like <code>multer</code> or <code>express-fileupload</code> intercepts this stream and temporarily writes it to a system-defined temporary directory (such as <code>/tmp</code> on Linux or <code>%TEMP%</code> on Windows).</p>
<p>This temporary stage is crucial. It ensures that incomplete, interrupted, or malformed uploads don’t pollute your permanent storage. Once the upload finishes successfully, your application logic takes over. You can then validate the file, rename it, and move it to a dedicated permanent directory like <code>uploads/</code>, <code>public/assets/</code>, or <code>storage/images/</code>.</p>
<p>Developers typically store metadata about the file (original name, new name, size, MIME type, and storage path) in a database. This separation of file storage and metadata keeps your system organized and makes it easy to retrieve files later.</p>
<h2>Local Storage vs. External Storage Concept</h2>
<p>Once you decide where to save files permanently, you face a fundamental architectural choice: <strong>local storage</strong> or <strong>external/cloud storage</strong>.</p>
<h3>Local Storage</h3>
<p>Local storage means saving files directly on your server’s filesystem. It’s straightforward, requires zero external configuration, and works perfectly for learning, prototyping, or small-scale apps.</p>
<p><strong>Pros:</strong></p>
<ul>
<li><p>Fast setup and zero external dependencies</p>
</li>
<li><p>Low latency for local reads/writes</p>
</li>
<li><p>Free (uses existing server disk)</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p>Doesn’t scale across multiple servers or containers</p>
</li>
<li><p>Manual backups and disk management required</p>
</li>
<li><p>Server migrations become complicated</p>
</li>
<li><p>Vulnerable to single-point hardware failure</p>
</li>
</ul>
<h3>External Storage</h3>
<p>External storage refers to cloud object storage services like AWS S3, Google Cloud Storage, Azure Blob, or specialized media platforms like Cloudinary and Uploadcare.</p>
<p><strong>Pros:</strong></p>
<ul>
<li><p>Horizontally scalable and highly available</p>
</li>
<li><p>Built-in CDN integration for fast global delivery</p>
</li>
<li><p>Automatic backups, versioning, and lifecycle policies</p>
</li>
<li><p>Decouples storage from your application servers</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p>Requires API setup and authentication</p>
</li>
<li><p>Incurs usage-based costs</p>
</li>
<li><p>Slightly more complex initial implementation</p>
</li>
</ul>
<p><strong>Best Practice:</strong> Start with local storage while learning, but design your upload service with an abstraction layer. This makes swapping to cloud storage later as simple as changing a configuration file rather than rewriting your entire codebase.</p>
<h2>Serving Static Files in Express</h2>
<p>Storing files is only half the equation. Users and browsers need to access them, and Express makes this effortless with its built-in <code>express.static()</code> middleware.</p>
<p>By default, Express does not expose your project directories to the web. This is a security feature. To safely serve uploaded files, you explicitly tell Express which folder should be publicly accessible:</p>
<pre><code class="language-javascript">const express = require('express');
const path = require('path');
const app = express();

// Serve files from the 'uploads' directory under the '/uploads' URL prefix
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));

app.listen(3000, () =&gt; console.log('Server running on http://localhost:3000'));
</code></pre>
<p>With this configuration, any file saved inside the <code>uploads/</code> folder becomes publicly accessible. The middleware automatically handles:</p>
<ul>
<li><p>Correct MIME type headers</p>
</li>
<li><p>Efficient byte-range requests (useful for video/audio streaming)</p>
</li>
<li><p>Basic caching headers</p>
</li>
<li><p>Secure path resolution (prevents directory traversal)</p>
</li>
</ul>
<p>Never use <code>express.static()</code> on your entire project root. Always isolate uploaded or public assets in a dedicated folder.</p>
<h2>Accessing Uploaded Files via URL</h2>
<p>Once static serving is configured, accessing files via URL becomes predictable and straightforward. When a file is uploaded, your backend should generate a safe, unique filename and store the relative path in your database.</p>
<p>For example, if a user with name: "Suprabhat", age: 23, uploads <code>avatar.png</code>, your backend might rename it to <code>user_8f3a2b_avatar.png</code> and save <code>/uploads/user_8f3a2b_avatar.png</code> in the database. Later, when rendering their profile, your frontend simply uses that path:</p>
<pre><code class="language-html">&lt;img src="/uploads/user_8f3a2b_avatar.png" alt="User Avatar" /&gt;
</code></pre>
<p>If you migrate to cloud storage, the flow remains identical. Instead of a local path, your database stores the full cloud URL: <code>https://your-bucket.s3.amazonaws.com/user_8f3a2b_avatar.png</code></p>
<p><strong>Important URL Guidelines:</strong></p>
<ul>
<li><p>Never expose internal server paths or absolute filesystem routes.</p>
</li>
<li><p>Always serve files through a controlled prefix (<code>/uploads/</code>, <code>/assets/</code>, etc.).</p>
</li>
<li><p>Avoid dynamic routes that directly map user input to file paths without strict validation.</p>
</li>
<li><p>Use consistent naming conventions to prevent broken links and cache conflicts.</p>
</li>
</ul>
<h2>Security Considerations for Uploads</h2>
<p>File uploads are consistently ranked among the top web application vulnerabilities. Without proper safeguards, attackers can upload malicious scripts, overwrite critical files, or exhaust your server’s disk space. Here’s how to lock down your upload pipeline:</p>
<h3>1. Validate File Types Properly</h3>
<p>Never trust the <code>Content-Type</code> header or file extension alone. Attackers can easily spoof them. Instead, inspect the file’s magic numbers (binary signature) using libraries like <code>file-type</code> or <code>mmmagic</code>. Maintain a strict allowlist (e.g., <code>image/jpeg</code>, <code>image/png</code>, <code>application/pdf</code>).</p>
<h3>2. Enforce File Size Limits</h3>
<p>Unrestricted uploads can trigger denial-of-service (DoS) attacks. Configure size limits directly in your middleware:</p>
<pre><code class="language-javascript">const upload = multer({
  limits: { fileSize: 5 * 1024 * 1024 } // 5MB max
});
</code></pre>
<h3>3. Sanitize and Rename Filenames</h3>
<p>User-provided filenames can contain path traversal sequences like <code>../../../etc/passwd</code> or executable extensions like <code>.php</code> or <code>.js</code>. Always strip dangerous characters and rename files using UUIDs, timestamps, or cryptographic hashes.</p>
<h3>4. Store Uploads Outside Executable Paths</h3>
<p>Ensure your server never executes files from the upload directory. Configure your hosting environment or reverse proxy (Nginx/Apache) to treat upload folders as static-only. If possible, store sensitive uploads outside the web root and serve them through authenticated routes.</p>
<h3>5. Implement Access Controls</h3>
<p>Not all uploads should be public. For private documents or user-specific media, bypass <code>express.static()</code> and serve files through a route that verifies authentication and ownership before streaming the file with <code>res.sendFile()</code>.</p>
<h3>6. Scan for Malware (Production Grade)</h3>
<p>For applications handling sensitive data or public submissions, integrate antivirus scanning using tools like ClamAV or cloud-based scanning APIs before permanently storing or serving files.</p>
<h2>Conclusion</h2>
<p>Handling file uploads might look simple on the surface, but it requires careful planning around storage architecture, accessibility, and security. Starting with local storage and Express’s <code>static</code> middleware gives you a solid foundation to understand the flow. As your application scales, transitioning to cloud storage and implementing strict validation will keep your system fast, reliable, and secure.</p>
<p>Remember the golden rules: never trust user input, always validate and sanitize, isolate upload directories, and design with both usability and safety in mind. With these practices, you’ll build file-handling features that work seamlessly for everyday users while keeping your infrastructure protected.</p>
<p>Ready to implement your first secure upload route? Spin up a local Express server, configure <code>multer</code>, apply the security checklist above, and watch your application handle files like a production-ready system. Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Sessions vs JWT vs Cookies: Understanding Authentication Approaches]]></title><description><![CDATA[Across the web, every time a user logs into a website, the server needs a way to remember who they are. But computers do not remember people by name. They need a reliable method to identify users acro]]></description><link>https://blog.suprabhat.site/sessions-vs-jwt-vs-cookies-understanding-authentication-approaches</link><guid isPermaLink="true">https://blog.suprabhat.site/sessions-vs-jwt-vs-cookies-understanding-authentication-approaches</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Session]]></category><category><![CDATA[JWT]]></category><category><![CDATA[cookies]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Tue, 28 Apr 2026 06:02:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/230efdfa-0d71-44ea-9d95-9be7fa6ffb1b.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Across the web, every time a user logs into a website, the server needs a way to remember who they are. But computers do not remember people by name. They need a reliable method to identify users across multiple requests.</p>
<p>In this blog we will understand what sessions are, what cookies are, what JWT tokens are, how stateful and stateless authentication differ, and when to use each method in real-world projects.</p>
<p>First, let's understand what is authentication and why it exists.</p>
<h2>What is authentication and why does it exist</h2>
<p>Authentication is how a website recognizes a user after they log in. When a user like name: "Suprabhat", age: 23 signs into an app, the server needs to know that the next request coming from the browser is still from the same person.</p>
<p>Without authentication, every page click would feel like a new visit. No saved cart, no profile page, no personalized content.</p>
<p>So how do we remember users? Three common approaches are used: Cookies, Sessions, and JWT tokens.</p>
<p>Let's understand each one.</p>
<h2>What are cookies and when are they used</h2>
<p>Cookies are small pieces of data stored in the user's browser. When a user logs in, the server can send a cookie to their browser. The browser then automatically includes that cookie in future requests to the same website.</p>
<pre><code class="language-javascript">// Server sets a cookie after login
res.cookie('userId', '12345', { maxAge: 24*60*60*1000 });
</code></pre>
<p>Cookies are stored on the client side, automatically sent with requests to the same domain, can have expiration times, and are limited to about 4KB of data.</p>
<p>Think of cookies like a library card. You show it each time you visit, and the librarian recognizes you.</p>
<p>When to use cookies:</p>
<ul>
<li><p>Remembering simple preferences like theme or language</p>
</li>
<li><p>Storing a session ID or token, not raw user data</p>
</li>
<li><p>Lightweight login persistence on single-domain sites</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/23615bf7-7c64-460e-8a57-a9afd5c2c620.png" alt="" style="display:block;margin:0 auto" />

<h2>What are sessions and why do we need them</h2>
<p>Sessions store user data on the server. When a user logs in, the server creates a unique session ID and sends it to the client, usually via a cookie. The client sends this ID back with each request, and the server looks up the ID to find the user's data.</p>
<p>How it works:</p>
<ol>
<li><p>User logs in, server creates session with sessionId and userId</p>
</li>
<li><p>Server sends sessionId to client via cookie</p>
</li>
<li><p>Client sends sessionId with each request</p>
</li>
<li><p>Server looks up sessionId to find user data</p>
</li>
</ol>
<p>Sessions keep data on the server, the client only holds a simple identifier, they are easy to invalidate by deleting the session, and they require server storage and lookup.</p>
<p>Think of sessions like a coat check. You get a ticket, and the staff keeps your actual coat safe.</p>
<p>When to use sessions:</p>
<ul>
<li><p>Traditional server-rendered apps like Django, Rails, or Express with EJS</p>
</li>
<li><p>When you need instant logout or permission updates</p>
</li>
<li><p>Single-domain applications with simple scaling needs</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/dc134af3-96f9-4f14-b119-bcdf7b4122d4.png" alt="" style="display:block;margin:0 auto" />

<h2>What are JWT tokens and how do they work</h2>
<p>JWT, which stands for JSON Web Tokens, are self-contained tokens that encode user information directly inside them. A JWT has three parts: header, payload, and signature. Once issued, the server can verify the token without storing anything.</p>
<pre><code class="language-javascript">// Server issues JWT after login
const token = jwt.sign({ userId: 123 }, 'secret', { expiresIn: '1h' });
// Client sends: Authorization: Bearer &lt;token&gt;
</code></pre>
<p>JWTs are stateless, meaning no server storage is needed. They contain encoded data, but you should not store secrets in the payload. They are signed to prevent tampering and have built-in expiration via the exp claim.</p>
<p>Think of JWTs like a signed event wristband. The bouncer can verify it is valid just by inspecting the wristband, no list needed.</p>
<p>When to use JWT:</p>
<ul>
<li><p>REST APIs or GraphQL backends</p>
</li>
<li><p>SPAs like React, Vue, or Angular, or mobile apps</p>
</li>
<li><p>Microservices or cross-domain authentication</p>
</li>
<li><p>When horizontal scaling is a priority</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/3eb7cc47-8da2-4847-b45f-fd9dcf4d33c5.png" alt="" style="display:block;margin:0 auto" />

<h2>What is the difference between stateful and stateless authentication</h2>
<table>
<thead>
<tr>
<th>Aspect</th>
<th>Stateful (Sessions)</th>
<th>Stateless (JWT)</th>
</tr>
</thead>
<tbody><tr>
<td>Server storage</td>
<td>Required</td>
<td>Not needed</td>
</tr>
<tr>
<td>Scaling</td>
<td>Needs shared store or sticky sessions</td>
<td>Easy to scale horizontally</td>
</tr>
<tr>
<td>Logout</td>
<td>Simple, delete session</td>
<td>Harder, need short expiry or allowlist</td>
</tr>
<tr>
<td>Performance</td>
<td>Lookup per request</td>
<td>Signature verify only</td>
</tr>
<tr>
<td>Best for</td>
<td>Monolithic web apps</td>
<td>APIs, mobile, microservices</td>
</tr>
</tbody></table>
<h2>Comparison table: Sessions vs JWT vs Cookies</h2>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Session-Based</th>
<th>JWT-Based</th>
<th>Cookie-Only</th>
</tr>
</thead>
<tbody><tr>
<td>Data location</td>
<td>Server</td>
<td>Token (client)</td>
<td>Client</td>
</tr>
<tr>
<td>Client stores</td>
<td>Session ID</td>
<td>Full token</td>
<td>Data or ID</td>
</tr>
<tr>
<td>Server lookup</td>
<td>Yes</td>
<td>No</td>
<td>Sometimes</td>
</tr>
<tr>
<td>Cross-domain</td>
<td>Limited</td>
<td>Yes with CORS</td>
<td>Same-domain only</td>
</tr>
<tr>
<td>Mobile friendly</td>
<td>Extra setup</td>
<td>Native support</td>
<td>Not ideal</td>
</tr>
<tr>
<td>Logout</td>
<td>Simple</td>
<td>Needs planning</td>
<td>Simple</td>
</tr>
<tr>
<td>Best use</td>
<td>Traditional web apps</td>
<td>APIs, SPAs, microservices</td>
<td>Simple preferences</td>
</tr>
</tbody></table>
<p>Note: Cookies are often used with sessions or JWTs to transport identifiers. They are a delivery method, not a complete auth strategy alone.</p>
<h2>When to use each method: real-world decisions</h2>
<p>Use Sessions when:</p>
<ul>
<li><p>Building a server-rendered website like an admin panel or blog CMS</p>
</li>
<li><p>You need immediate access revocation</p>
</li>
<li><p>Your app runs on one domain</p>
</li>
<li><p>You are learning and want simpler debugging</p>
</li>
</ul>
<p>Example: An internal tool where name: "Suprabhat", age: 23 manages content. Sessions let you revoke access instantly.</p>
<p>Use JWT when:</p>
<ul>
<li><p>Building a public API or backend for a mobile app</p>
</li>
<li><p>Your frontend and backend are separate, like SPA plus API</p>
</li>
<li><p>You need authentication across services or domains</p>
</li>
<li><p>You want to scale without shared session storage</p>
</li>
</ul>
<p>Example: A fitness app where users log in once and access APIs from phone, web, and watch. JWTs travel easily in headers.</p>
<p>Use simple Cookies when:</p>
<ul>
<li><p>Storing non-sensitive preferences like theme or language</p>
</li>
<li><p>Lightweight remember me for simple sites</p>
</li>
<li><p>Transporting a session ID or token, not the data itself</p>
</li>
</ul>
<p>Example: A news site that remembers your preferred category. A simple cookie is enough.</p>
<h2>Conclusion</h2>
<p>Authentication does not have to be confusing.</p>
<p>Cookies are small data pieces the browser stores and sends automatically. Sessions keep user data on the server and use a cookie to share an ID. JWTs pack user data into a signed token the server can verify without storage.</p>
<p>Choosing between them depends on your project. Need simplicity and control, go with Sessions. Building APIs or mobile apps, choose JWT. Just remembering preferences, simple cookies work.</p>
<p>Your next step: Build a tiny login with sessions. Then rebuild it with JWT. Compare the experience. Hands-on practice beats any tutorial.</p>
<p>Understanding these basics helps you see how the invisible parts of authentication work every time a user logs in.</p>
]]></content:encoded></item><item><title><![CDATA[URL Parameters vs Query Strings in Express.js]]></title><description><![CDATA[Every web application relies on URLs to navigate, fetch data, and trigger actions. But not all URLs are structured the same way. Some carry data directly in the path, while others append information a]]></description><link>https://blog.suprabhat.site/url-parameters-vs-query-strings-in-express-js</link><guid isPermaLink="true">https://blog.suprabhat.site/url-parameters-vs-query-strings-in-express-js</guid><category><![CDATA[Express]]></category><category><![CDATA[url]]></category><category><![CDATA[Query]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Mon, 27 Apr 2026 16:42:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/822657b2-54aa-4e2d-9b3d-7407d64ed1e7.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every web application relies on URLs to navigate, fetch data, and trigger actions. But not all URLs are structured the same way. Some carry data directly in the path, while others append information after a question mark. Understanding the difference between URL parameters and query parameters is essential for building clean, predictable, and RESTful APIs.</p>
<p>In this guide, we’ll break down what each type is, how they differ, how to access them in Express, and when to use one over the other. By the end, you’ll know exactly how to structure your routes and handle incoming data with confidence.</p>
<h2>What Are URL Parameters?</h2>
<p>URL parameters (also called path parameters or route parameters) are dynamic segments embedded directly into the URL path. They act as placeholders for specific values that your application needs to identify a resource.</p>
<p>For example:</p>
<pre><code class="language-plaintext">/users/42
/posts/javascript-basics
/orders/ORD-9981/items
</code></pre>
<p>In these URLs, <code>42</code>, <code>javascript-basics</code>, and <code>ORD-9981</code> are URL parameters. They are <strong>required</strong> for the route to match and typically represent unique identifiers, slugs, or hierarchical relationships. Think of them as the exact "address" of a specific item in your system. If you remove or change a URL parameter, you’re requesting a completely different resource.</p>
<h2>What Are Query Parameters?</h2>
<p>Query parameters appear after the <code>?</code> character in a URL and are formatted as key-value pairs. Multiple pairs are separated by <code>&amp;</code>.</p>
<p>For example:</p>
<pre><code class="language-plaintext">/products?category=electronics&amp;sort=price&amp;limit=10
/users?role=admin&amp;active=true
/search?q=express+tutorial&amp;page=2
</code></pre>
<p>Unlike URL parameters, query parameters are <strong>optional</strong> and do not change the base route. They are primarily used to modify how a resource is retrieved or displayed. Common use cases include filtering, sorting, pagination, search terms, and toggling view modes. The same endpoint can behave differently based on the query string attached to it, making query parameters highly flexible.</p>
<h2>Key Differences Between URL and Query Parameters</h2>
<table>
<thead>
<tr>
<th>Feature</th>
<th>URL Parameters</th>
<th>Query Parameters</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Location</strong></td>
<td>Inside the path (<code>/users/:id</code>)</td>
<td>After <code>?</code> (<code>/users?role=admin</code>)</td>
</tr>
<tr>
<td><strong>Syntax</strong></td>
<td>Defined with <code>:</code> in route definitions</td>
<td>Key-value pairs separated by <code>&amp;</code></td>
</tr>
<tr>
<td><strong>Required?</strong></td>
<td>Yes (route won’t match without them)</td>
<td>No (base route works fine without them)</td>
</tr>
<tr>
<td><strong>Primary Purpose</strong></td>
<td>Identify a specific resource</td>
<td>Filter, sort, paginate, or modify response</td>
</tr>
<tr>
<td><strong>REST Convention</strong></td>
<td>Used for resource hierarchy &amp; IDs</td>
<td>Used for optional modifiers &amp; search</td>
</tr>
<tr>
<td><strong>Caching &amp; SEO</strong></td>
<td>Treated as unique URLs by browsers/CDNs</td>
<td>Often ignored or handled separately</td>
</tr>
</tbody></table>
<p>Understanding these differences helps you design routes that are intuitive, scalable, and aligned with industry standards.</p>
<h2>Accessing Params in Express</h2>
<p>Express makes working with URL parameters straightforward. You define them in your route path using a colon (<code>:</code>), and Express automatically extracts them into the <code>req.params</code> object.</p>
<pre><code class="language-javascript">const express = require('express');
const app = express();

// Define a route with a URL parameter
app.get('/users/:userId', (req, res) =&gt; {
  const userId = req.params.userId;
  
  // Mock database response
  const user = {
    id: userId,
    name: "Suprabhat",
    age: 23,
    role: "developer"
  };

  res.json(user);
});

app.listen(3000, () =&gt; console.log('Server running on port 3000'));
</code></pre>
<p>When a client requests <code>/users/42</code>, Express matches the route, extracts <code>42</code>, and assigns it to <code>req.params.userId</code>. You can define multiple parameters in a single route (e.g., <code>/posts/:postId/comments/:commentId</code>), and Express will parse each one into the <code>req.params</code> object.</p>
<p><strong>Note:</strong> URL parameters are always returned as strings. If you need numbers or booleans, you must explicitly convert them using <code>parseInt()</code>, <code>Number()</code>, or validation middleware.</p>
<h2>Accessing Query Strings in Express</h2>
<p>You don’t need to define query parameters in your route path. Express automatically parses everything after the <code>?</code> and populates the <code>req.query</code> object.</p>
<pre><code class="language-javascript">app.get('/products', (req, res) =&gt; {
  const { category, sort, limit } = req.query;

  // Default values if query params are missing
  const safeLimit = limit ? parseInt(limit, 10) : 20;
  const safeSort = sort || 'createdAt';

  res.json({
    message: 'Fetching products',
    filters: { category, sort: safeSort, limit: safeLimit }
  });
});
</code></pre>
<p>A request to <code>/products?category=books&amp;sort=price&amp;limit=5</code> will result in:</p>
<pre><code class="language-json">req.query = {
  category: 'books',
  sort: 'price',
  limit: '5'
}
</code></pre>
<p>Express uses the <code>qs</code> library under the hood, which also supports nested objects and arrays (e.g., <code>?tags=node&amp;tags=express</code> becomes <code>{ tags: ['node', 'express'] }</code>). Like URL params, query values are always strings, so type conversion or validation is recommended before using them in database queries or business logic.</p>
<h2>When to Use Params vs Query</h2>
<p>Choosing between URL parameters and query parameters isn’t just a stylistic preference. It impacts API design, caching, SEO, and developer experience. Follow these practical guidelines:</p>
<h3>Use URL Parameters When:</h3>
<ul>
<li><p>You’re identifying a <strong>specific resource</strong> (<code>/users/123</code>, <code>/orders/ORD-55</code>)</p>
</li>
<li><p>The value is <strong>required</strong> for the route to make sense</p>
</li>
<li><p>You’re building <strong>RESTful endpoints</strong> that follow resource hierarchy</p>
</li>
<li><p>You want clean, bookmarkable URLs for individual items</p>
</li>
<li><p>The parameter represents a <strong>primary key, slug, or unique identifier</strong></p>
</li>
</ul>
<h3>Use Query Parameters When:</h3>
<ul>
<li><p>You’re <strong>filtering, sorting, or paginating</strong> a collection (<code>?status=active&amp;page=2</code>)</p>
</li>
<li><p>The data is <strong>optional</strong> or has sensible defaults</p>
</li>
<li><p>You’re handling <strong>search terms</strong> (<code>?q=express+routing</code>)</p>
</li>
<li><p>You need to pass <strong>multiple modifiers</strong> without creating endless route combinations</p>
</li>
<li><p>You want to keep your route structure flat and maintainable</p>
</li>
</ul>
<h3>Common Mistakes to Avoid:</h3>
<ul>
<li><p>Putting optional filters in the path (<code>/users/active/sorted-by-name</code>) → Use query params instead.</p>
</li>
<li><p>Using query params for required resource IDs (<code>/users?id=42</code>) → Breaks REST conventions and hurts caching.</p>
</li>
<li><p>Mixing both for the same purpose → Confuses API consumers and complicates documentation.</p>
</li>
</ul>
<p>A good rule of thumb: <strong>Path params answer "which one?", query params answer "how should I show it?"</strong></p>
<h2>Conclusion</h2>
<p>URL parameters and query parameters serve different but complementary roles in web development. URL parameters lock down the identity of a resource, while query parameters give you the flexibility to shape how that resource is delivered. Express handles both elegantly through <code>req.params</code> and <code>req.query</code>, allowing you to build clean, predictable routes without boilerplate parsing logic.</p>
<p>As you design your endpoints, remember to align your choices with REST principles, keep required identifiers in the path, and reserve the query string for optional modifiers. Validate and sanitize all incoming values, convert types explicitly, and document your expected parameters clearly.</p>
<p>With this foundation, you’ll craft APIs that are intuitive for frontend developers, cache-friendly for CDNs, and scalable as your application grows. Spin up an Express server, experiment with different route combinations, and watch how cleanly your app can handle dynamic requests. Happy routing!</p>
]]></content:encoded></item><item><title><![CDATA[What is Middleware in Express and How It Works]]></title><description><![CDATA[If you’ve ever written an Express server, you’ve already used middleware. That app.use(express.json()) line at the top of your file? Middleware. That function checking if a user is logged in before ac]]></description><link>https://blog.suprabhat.site/what-is-middleware-in-express</link><guid isPermaLink="true">https://blog.suprabhat.site/what-is-middleware-in-express</guid><category><![CDATA[Middleware]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Mon, 27 Apr 2026 06:50:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/48d39f2b-fcac-4431-a256-bc39dff27dd6.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’ve ever written an Express server, you’ve already used middleware. That <code>app.use(express.json())</code> line at the top of your file? Middleware. That function checking if a user is logged in before accessing a dashboard? Also middleware.</p>
<p>But what exactly is middleware? Why does Express rely on it so heavily? And why does the order you write it in matter so much?</p>
<p>In this beginner-friendly guide, we’ll demystify Express middleware, walk through where it fits in the request lifecycle, break down its types, and build real-world examples you can use in your own projects.</p>
<h2>What is Middleware in Express?</h2>
<p>At its core, <strong>middleware is just a function</strong>. But it’s a function with special access. Every middleware function receives three arguments:</p>
<ul>
<li><p><code>req</code> (the incoming request object)</p>
</li>
<li><p><code>res</code> (the outgoing response object)</p>
</li>
<li><p><code>next</code> (a function that passes control to the next middleware)</p>
</li>
</ul>
<p>Middleware sits between the raw HTTP request and your final route handler. It can:</p>
<ul>
<li><p>Read or modify <code>req</code> and <code>res</code></p>
</li>
<li><p>Execute code (like logging or validation)</p>
</li>
<li><p>End the request-response cycle early (by sending a response)</p>
</li>
<li><p>Pass control to the next middleware using <code>next()</code></p>
</li>
</ul>
<p>Think of middleware like a series of security checkpoints at an airport. Your request is the passenger. Each checkpoint inspects, stamps, or redirects the passenger before they finally reach the gate (your route handler).</p>
<h2>Where Middleware Sits in the Request Lifecycle</h2>
<p>When a request hits your Express server, it doesn’t jump straight to your route logic. Instead, it flows through a <strong>middleware pipeline</strong>:</p>
<ol>
<li><p>Request arrives at the server</p>
</li>
<li><p>Passes through global/application middleware</p>
</li>
<li><p>Passes through router-specific middleware (if matched)</p>
</li>
<li><p>Reaches the final route handler</p>
</li>
<li><p>Response is sent back to the client</p>
</li>
</ol>
<p>At any point in this chain, a middleware can:</p>
<ul>
<li><p>Modify the request (e.g., parse JSON, attach a user object)</p>
</li>
<li><p>Reject the request (e.g., return <code>401 Unauthorized</code>)</p>
</li>
<li><p>Log data, set headers, or handle errors</p>
</li>
<li><p>Call <code>next()</code> to continue the journey</p>
</li>
</ul>
<p>If no middleware sends a response and <code>next()</code> is never called, the request will hang until it times out. This is why understanding the flow is critical.</p>
<h2>The Role of the <code>next()</code> Function</h2>
<p>The <code>next()</code> function is the traffic controller of Express middleware. It tells the server: <em>“I’m done processing. Move to the next function in line.”</em></p>
<p>Here’s what happens depending on how you use it:</p>
<ul>
<li><p><code>next()</code> → Moves to the next matching middleware or route</p>
</li>
<li><p><code>next(err)</code> → Skips all regular middleware and jumps to error-handling middleware</p>
</li>
<li><p>Forgetting <code>next()</code> → The request hangs forever (a common beginner bug)</p>
</li>
</ul>
<pre><code class="language-javascript">app.use((req, res, next) =&gt; {
  console.log("Request received!");
  next(); // Without this, the browser will spin indefinitely
});
</code></pre>
<p><code>next()</code> is what makes middleware composable. You can chain dozens of functions together, and Express will execute them in order, as long as each one calls <code>next()</code>.</p>
<h2>Why Execution Order Matters</h2>
<p>Middleware runs <strong>exactly in the order you define it</strong>. This isn’t a suggestion; it’s the architecture.</p>
<p>If you place authentication middleware before <code>express.json()</code>, your auth logic might try to read <code>req.body</code> before it’s parsed, resulting in <code>undefined</code>. If you place a catch-all route before your API routes, those API routes will never be reached.</p>
<pre><code class="language-javascript">// ✅ Correct order
app.use(express.json());           // Parse body first
app.use(authMiddleware);           // Then check auth
app.get("/dashboard", handler);    // Finally handle route

// ❌ Broken order
app.use(authMiddleware);           // Tries to read unparsed body
app.use(express.json());           // Too late
</code></pre>
<p>Always arrange middleware from <strong>broad to specific</strong>, and from <strong>data preparation to business logic</strong>.</p>
<h2>Types of Middleware in Express</h2>
<p>Express categorizes middleware based on where and how it’s applied. Here are the three main types you’ll use daily:</p>
<h3>1. Application-Level Middleware</h3>
<p>Bound to the entire <code>app</code> instance using <code>app.use()</code> or <code>app.METHOD()</code>. Runs on every request (or a specific path if provided).</p>
<pre><code class="language-javascript">app.use((req, res, next) =&gt; {
  console.log(`\({req.method} \){req.url}`);
  next();
});
</code></pre>
<h3>2. Router-Level Middleware</h3>
<p>Works exactly like application-level middleware, but is bound to an instance of <code>express.Router()</code>. Ideal for modularizing features.</p>
<pre><code class="language-javascript">const router = express.Router();

router.use((req, res, next) =&gt; {
  console.log("Router middleware triggered");
  next();
});

router.get("/users", (req, res) =&gt; res.send("User list"));
app.use("/api", router);
</code></pre>
<h3>3. Built-In Middleware</h3>
<p>Express ships with a few essential middleware functions out of the box:</p>
<ul>
<li><p><code>express.json()</code> → Parses incoming JSON payloads</p>
</li>
<li><p><code>express.urlencoded({ extended: true })</code> → Parses form data</p>
</li>
<li><p><code>express.static("public")</code> → Serves static files like CSS, images, or JS</p>
</li>
</ul>
<p>You don’t need to install anything extra. Just plug them in at the top of your server file.</p>
<h2>Real-World Middleware Examples</h2>
<p>Theory is great, but middleware shines in practice. Here are three production-ready patterns you’ll use constantly.</p>
<h3>1. Request Logging</h3>
<p>Track every incoming request for debugging or analytics.</p>
<pre><code class="language-javascript">app.use((req, res, next) =&gt; {
  const timestamp = new Date().toISOString();
  console.log(`[\({timestamp}] \){req.method} ${req.url}`);
  next();
});
</code></pre>
<h3>2. Authentication Guard</h3>
<p>Protect routes by verifying a token before allowing access.</p>
<pre><code class="language-javascript">const authMiddleware = (req, res, next) =&gt; {
  const token = req.headers.authorization;

  if (!token) {
    return res.status(401).json({ error: "No token provided" });
  }

  // In real apps, verify JWT or session here
  req.user = { name: "Suprabhat", age: 23, role: "admin" };
  next();
};

app.get("/profile", authMiddleware, (req, res) =&gt; {
  res.json({ message: `Welcome, ${req.user.name}` });
});
</code></pre>
<h3>3. Request Validation</h3>
<p>Ensure required fields exist before hitting your database.</p>
<pre><code class="language-javascript">const validateUser = (req, res, next) =&gt; {
  const { name, email } = req.body;

  if (!name || !email) {
    return res.status(400).json({ error: "Name and email are required" });
  }

  next();
};

app.post("/register", express.json(), validateUser, (req, res) =&gt; {
  res.status(201).json({ message: "User registered successfully" });
});
</code></pre>
<p>Notice how each middleware does <strong>one thing well</strong>, then passes control forward. That’s the Express philosophy.</p>
<h2>Conclusion</h2>
<p>Middleware is the backbone of Express. It’s how you parse data, secure routes, log activity, handle errors, and structure your backend without cluttering your route handlers. Once you understand the request pipeline, the power of <code>next()</code>, and why order matters, you’ll stop fighting Express and start leveraging it.</p>
<p>Start small. Write a logger. Add a validation check. Experiment with moving middleware up and down your file to see how the flow changes. The more you play with the pipeline, the more intuitive it becomes.</p>
<p>Express doesn’t force a rigid architecture. It gives you a flexible, composable system where every function has a clear job. Middleware is that system in action.</p>
]]></content:encoded></item><item><title><![CDATA[Async Code in Node.js: Callbacks and Promises]]></title><description><![CDATA[When you start learning Node.js, one concept appears everywhere: asynchronous code. If you come from a background where programs run line by line, this can feel confusing. Why does Node.js handle oper]]></description><link>https://blog.suprabhat.site/async-code-in-node-js-callbacks-and-promises</link><guid isPermaLink="true">https://blog.suprabhat.site/async-code-in-node-js-callbacks-and-promises</guid><category><![CDATA[promises]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sun, 26 Apr 2026 16:56:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/4b8922c1-a6d8-4119-9004-e7f9011223fc.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you start learning Node.js, one concept appears everywhere: asynchronous code. If you come from a background where programs run line by line, this can feel confusing. Why does Node.js handle operations differently? Why can’t we just wait for each step to finish? In this blog, we will break down why async code exists in Node.js, how callbacks work, why nested callbacks become problematic, and how promises solve these issues. By the end, you will have a clear mental model of how Node.js handles asynchronous operations.</p>
<h2>Why Async Code Exists in Node.js</h2>
<p>Node.js is built on a single-threaded event loop. This means it can only execute one instruction at a time. At first glance, this sounds limiting. But the internet is full of slow operations: reading files, querying databases, making external API calls, or waiting for user input. If Node.js waited for each of these to finish before moving to the next line, the entire application would freeze. This is called blocking.</p>
<p>To solve this, Node.js uses asynchronous execution. Instead of waiting, it starts a slow operation, registers a function to run when the operation finishes, and immediately moves to the next task. When the slow operation completes, the event loop picks up the registered function and executes it. This keeps the application fast and responsive, even under heavy load.</p>
<p>Think of it like ordering food at a busy café. You don’t stand at the counter waiting for your meal. You get a receipt with an order number, step aside, and maybe check your phone. When your food is ready, you are called to pick it up. Async code works the same way: start the task, step aside, and get notified when it’s done.</p>
<h2>Callback-Based Async Execution</h2>
<p>In the early days of Node.js, asynchronous operations relied heavily on callbacks. A callback is simply a function passed as an argument to another function, which gets executed later when a task finishes.</p>
<p>Consider a basic file-reading example:</p>
<pre><code class="language-javascript">const fs = require('fs');

fs.readFile('data.txt', 'utf8', (err, data) =&gt; {
  if (err) {
    console.error('Failed to read file:', err);
    return;
  }
  console.log('File content:', data);
});

console.log('This message prints first!');
</code></pre>
<p>Here, <code>readFile</code> starts reading the file in the background. The callback <code>(err, data) =&gt; { ... }</code> waits in line. Meanwhile, <code>console.log('This message prints first!')</code> executes immediately. When the file finishes reading, the event loop triggers the callback. This pattern keeps Node.js non-blocking and highly efficient for I/O-heavy applications.</p>
<h2>Problems with Nested Callbacks</h2>
<p>Callbacks work well for one or two operations. But real-world applications often require multiple sequential steps. You might need to read a configuration file, then query a database, then format the result, and finally send a response. When you chain callbacks inside callbacks, code quickly becomes difficult to read and maintain. Developers call this “Callback Hell” or the “Pyramid of Doom.”</p>
<pre><code class="language-javascript">fs.readFile('config.json', 'utf8', (err, config) =&gt; {
  if (err) return console.error(err);
  db.connect(config.dbUrl, (err, client) =&gt; {
    if (err) return console.error(err);
    client.query('SELECT * FROM users', (err, users) =&gt; {
      if (err) return console.error(err);
      console.log('Fetched users:', users);
    });
  });
});
</code></pre>
<p>This structure introduces several serious problems:</p>
<ul>
<li><p><strong>Readability drops quickly:</strong> The code shifts to the right with every new step, breaking natural reading flow.</p>
</li>
<li><p><strong>Error handling is repetitive:</strong> Every callback needs its own <code>if (err)</code> block, violating the DRY (Don’t Repeat Yourself) principle.</p>
</li>
<li><p><strong>State management gets messy:</strong> Variables from outer scopes must be manually passed down or scoped carefully.</p>
</li>
<li><p><strong>Debugging becomes painful:</strong> Stack traces grow long, and tracking where an error originated takes extra effort.</p>
</li>
</ul>
<p>Imagine a junior developer, name: "Suprabhat", age: 23, trying to maintain a feature built this way. Adding a new step or fixing a bug requires untangling the pyramid, which slows down development and increases the chance of introducing new errors.</p>
<h2>Promise-Based Async Handling</h2>
<p>Promises were introduced to solve callback hell. A promise is an object that represents the eventual completion (or failure) of an asynchronous operation. Instead of passing a callback, a function returns a promise. You attach handlers to that promise using <code>.then()</code> for success and <code>.catch()</code> for errors.</p>
<p>A promise exists in one of three states:</p>
<ul>
<li><p><strong>Pending:</strong> The operation is still running.</p>
</li>
<li><p><strong>Fulfilled:</strong> The operation completed successfully.</p>
</li>
<li><p><strong>Rejected:</strong> The operation failed with an error.</p>
</li>
</ul>
<p>Let’s rewrite the previous example using promises:</p>
<pre><code class="language-javascript">const fs = require('fs').promises;

fs.readFile('config.json', 'utf8')
  .then(config =&gt; db.connect(config.dbUrl))
  .then(client =&gt; client.query('SELECT * FROM users'))
  .then(users =&gt; console.log('Fetched users:', users))
  .catch(err =&gt; console.error('Something failed:', err));
</code></pre>
<p>Notice how the flow is flatter and more readable. Each <code>.then()</code> receives the result of the previous step and passes its own result forward. Errors automatically bubble down to a single <code>.catch()</code>, eliminating repetitive error checks.</p>
<h2>Benefits of Promises</h2>
<p>Moving from callbacks to promises brings several practical advantages that directly impact developer productivity and code quality:</p>
<ul>
<li><p><strong>Cleaner, linear code:</strong> No more rightward drift. Code flows top-to-bottom, matching how we naturally read and reason about logic.</p>
</li>
<li><p><strong>Centralized error handling:</strong> One <code>.catch()</code> at the end handles errors from any step in the chain. You no longer need scattered <code>if (err)</code> blocks.</p>
</li>
<li><p><strong>Better composability:</strong> Promises can be combined using <code>Promise.all()</code>, <code>Promise.race()</code>, or <code>Promise.allSettled()</code>. This makes running parallel tasks straightforward and predictable.</p>
</li>
<li><p><strong>Foundation for modern syntax:</strong> Promises paved the way for <code>async</code> and <code>await</code>. Under the hood, <code>await</code> is simply pausing execution until a promise settles, letting you write asynchronous code that looks synchronous.</p>
</li>
<li><p><strong>Predictable execution order:</strong> Promises guarantee that <code>.then()</code> callbacks run in the order they are attached, avoiding race conditions that often plague callback-heavy code.</p>
</li>
</ul>
<p>For teams, this translates to faster feature development, easier code reviews, and more reliable production systems.</p>
<h2>Conclusion</h2>
<p>Asynchronous programming is the backbone of Node.js. It exists because modern applications spend most of their time waiting for external I/O, not performing heavy computations. Callbacks were the first solution, but nested callbacks quickly became unmanageable as applications grew. Promises solved this by introducing a structured, chainable way to handle async operations, with cleaner syntax and centralized error handling. Understanding this evolution is crucial for any Node.js developer. Once you master promises, you will find that modern features like <code>async/await</code> become second nature. The next time you build an API, read a database, or call an external service, remember: you are not just writing code, you are orchestrating time. Keep experimenting, chain those promises, and let the event loop do its work efficiently.</p>
]]></content:encoded></item><item><title><![CDATA[How Node.js Handles Multiple Requests with a Single Thread]]></title><description><![CDATA[When you first hear that Node.js is “single-threaded,” it sounds like a major limitation. How can a single thread handle thousands of simultaneous users without freezing? The secret lies in Node.js’s ]]></description><link>https://blog.suprabhat.site/how-node-js-handles-multiple-requests-with-a-single-thread</link><guid isPermaLink="true">https://blog.suprabhat.site/how-node-js-handles-multiple-requests-with-a-single-thread</guid><category><![CDATA[Node.js]]></category><category><![CDATA[node]]></category><category><![CDATA[ChaiCode]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sun, 26 Apr 2026 15:47:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/4404f321-1b03-4923-8474-db50ef43a8b3.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you first hear that Node.js is “single-threaded,” it sounds like a major limitation. How can a single thread handle thousands of simultaneous users without freezing? The secret lies in Node.js’s clever architecture. Instead of relying on traditional multi-threading, Node.js uses an event-driven model, a non-blocking I/O system, and background task delegation to manage concurrency efficiently. In this guide, we will break down exactly how Node.js handles multiple requests, why the event loop is the heart of its performance, and how this design allows applications to scale effortlessly. Whether you are building a real-time chat app, an API, or a microservice, understanding these concepts will help you write faster, more resilient code.</p>
<h2>The Single-Threaded Nature of Node.js</h2>
<p>Unlike traditional web servers like Apache or Java-based servers, which spawn a new thread for every incoming request, Node.js runs its main execution logic on a single thread. This might sound restrictive, but it is actually a deliberate design choice. Threads consume significant memory and require constant context switching by the CPU, which can slow down a server under heavy load. By sticking to one main thread, Node.js keeps memory usage remarkably low and avoids the overhead of managing dozens or hundreds of parallel threads.</p>
<p>However, “single-threaded” does not mean “single-tasking” or “blocking.” Node.js is explicitly designed to never stall that main thread. Instead of waiting for a database query, file read, or network call to finish, it registers a callback and immediately moves on to the next task. When the external operation completes, the result is queued for execution. This non-blocking behavior is what makes Node.js feel like it is doing many things at once, even though only one line of your JavaScript code runs at any given moment.</p>
<h2>The Event Loop’s Role in Concurrency</h2>
<p>The magic behind Node.js concurrency is the event loop. Think of it as a continuous traffic controller that never sleeps. When your application starts, the event loop begins running in the background. Its job is simple but powerful: continuously check if there are any pending callbacks, execute them in order, and repeat.</p>
<p>The event loop operates in distinct phases, each responsible for handling different types of tasks like timers, I/O callbacks, idle checks, and immediate execution. When you make an asynchronous call, like fetching data from an external API or querying a database, Node.js hands that request off to the underlying operating system or background workers. Your main thread immediately continues executing the next lines of code. Once the external operation finishes, the result is placed in a callback queue. The event loop picks it up during the appropriate phase and executes your registered function.</p>
<p>This model allows Node.js to manage thousands of concurrent connections without creating a dedicated thread for each one. As long as your JavaScript callbacks execute quickly and avoid heavy synchronous computations, the event loop stays highly responsive, and your server remains fast under pressure.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/cd9d28c3-66dd-4c4c-bf71-5467cd11d91a.png" alt="" style="display:block;margin:0 auto" />

<h2>Delegating Tasks to Background Workers</h2>
<p>While JavaScript itself runs on a single main thread, Node.js is not entirely working alone. Under the hood, it relies on <code>libuv</code>, a powerful C library that handles asynchronous I/O operations across different operating systems. <code>libuv</code> maintains a thread pool (typically four threads by default) to offload tasks that cannot be handled purely by the OS’s non-blocking APIs.</p>
<p>These delegated tasks include file system operations, DNS resolution, compression, and cryptographic functions. When you call <code>fs.readFile()</code> or use the <code>crypto</code> module, Node.js routes the work to the <code>libuv</code> thread pool. The main thread continues running your application logic, and once the background thread finishes, it notifies the event loop. For even heavier JavaScript workloads, Node.js provides the <code>Worker Threads</code> module, which lets you run CPU-intensive JavaScript code in true parallel threads without blocking the main event loop. This layered delegation ensures that long-running tasks do not choke your application’s responsiveness.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/e8a9fe4f-8058-4b86-9dcf-dbb5ef59bc6d.png" alt="" style="display:block;margin:0 auto" />

<h2>Handling Multiple Client Requests</h2>
<p>Let’s see how this architecture works in a real-world scenario. Imagine a user with <code>name: "Suprabhat", age: 23,</code> visits your e-commerce platform. At the exact same moment, hundreds of other users are browsing products, adding items to carts, and checking out. In a traditional multi-threaded server, each request might consume a dedicated thread, quickly exhausting memory and CPU resources. In Node.js, the main thread accepts each connection, registers the required asynchronous operations (like database reads or external payment API calls), and immediately returns control to the event loop.</p>
<p>While Suprabhat’s request waits for a database response, Node.js is already processing the next user’s request. When the database finally replies, the event loop queues the callback, executes it, formats the JSON response, and sends it back to Suprabhat’s browser. This cycle repeats continuously. Because I/O operations are handled asynchronously and delegated to the OS or background threads, the main thread spends almost all its time accepting new connections and processing ready callbacks, not idly waiting.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/b6bd925f-4a20-4ddf-b67a-8cd4800f8396.png" alt="" style="display:block;margin:0 auto" />

<h2>Why Node.js Scales Well</h2>
<p>Node.js scales exceptionally well for I/O-bound applications, which cover the vast majority of modern web APIs, real-time dashboards, and microservices. Its low memory footprint means you can run many instances on a single server or distribute them across a containerized cluster. Tools like PM2 or the built-in <code>cluster</code> module allow you to fork the single-threaded process across multiple CPU cores, effectively multiplying your server’s capacity without rewriting your application code.</p>
<p>The event-driven architecture also aligns perfectly with modern cloud infrastructure. Load balancers can distribute incoming TCP/HTTP traffic across multiple Node.js instances, and because each instance handles thousands of concurrent connections efficiently, horizontal scaling becomes straightforward and cost-effective. While Node.js is not ideal for heavy CPU-bound tasks like video encoding or complex mathematical simulations (unless you explicitly use Worker Threads or offload to specialized services), it shines in real-time applications, REST/GraphQL APIs, streaming platforms, and collaborative tools.</p>
<h2>Conclusion</h2>
<p>Node.js proves that high concurrency does not require multi-threaded complexity. By combining a single-threaded event loop, non-blocking I/O, and intelligent background delegation, it delivers remarkable performance and predictable scalability. Understanding how the event loop orchestrates requests and how tasks are offloaded behind the scenes empowers you to write efficient, production-ready applications. As you continue building with Node.js, keep the event loop in mind, avoid blocking synchronous calls, and leverage background workers when heavy lifting is required. The result? Fast, scalable, and resilient applications that handle real-world traffic with ease.</p>
]]></content:encoded></item><item><title><![CDATA[What is Node.js? JavaScript on the Server Explained]]></title><description><![CDATA[If you started learning web development a decade ago, you were probably told one golden rule: JavaScript lives in the browser. It was the language of button clicks, form validations, and animated drop]]></description><link>https://blog.suprabhat.site/what-is-node-js</link><guid isPermaLink="true">https://blog.suprabhat.site/what-is-node-js</guid><category><![CDATA[Node.js]]></category><category><![CDATA[node]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sun, 26 Apr 2026 15:01:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/b220593e-1243-41cf-9249-dbb58172b9dd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you started learning web development a decade ago, you were probably told one golden rule: <strong>JavaScript lives in the browser.</strong> It was the language of button clicks, form validations, and animated dropdowns. Servers? Those belonged to PHP, Python, Java, or Ruby.</p>
<p>Then came Node.js, and everything changed.</p>
<p>Today, JavaScript powers everything from frontend interfaces to backend APIs, real-time chat apps, and even command-line tools. But how did a browser scripting language suddenly run on servers? What makes Node.js different? And why do companies like Netflix, Uber, and LinkedIn rely on it?</p>
<p>In this beginner-friendly guide, we’ll break down exactly what Node.js is, why JavaScript was originally trapped in the browser, how Node.js set it free, and the core ideas that make it so powerful.</p>
<h2>What Exactly is Node.js?</h2>
<p>Let’s clear up a common misconception right away: <strong>Node.js is not a programming language, and it’s not a framework.</strong></p>
<p>Node.js is a <strong>runtime environment</strong>. In simple terms, it’s a platform that allows JavaScript code to run outside of a web browser. It provides the necessary tools, libraries, and system access so JavaScript can interact with your computer’s operating system, read files, open network ports, and handle server requests.</p>
<p>Think of it like an engine stand. JavaScript is the engine, and Node.js is the stand that lets you run that engine in a garage instead of inside a car.</p>
<h2>Why JavaScript Was Originally Browser-Only</h2>
<p>JavaScript was created in 1995 by Brendan Eich at Netscape with a very specific goal: make web pages interactive. It was designed to run inside browsers, and for security reasons, browsers intentionally sandboxed it.</p>
<p>This sandbox meant JavaScript could:</p>
<ul>
<li><p>Manipulate HTML and CSS</p>
</li>
<li><p>Respond to user clicks and keyboard input</p>
</li>
<li><p>Make limited network requests (later via AJAX)</p>
</li>
</ul>
<p>But it <strong>could not</strong>:</p>
<ul>
<li><p>Read or write files on your computer</p>
</li>
<li><p>Open raw network sockets</p>
</li>
<li><p>Access system processes or hardware</p>
</li>
<li><p>Run independently without a browser tab open</p>
</li>
</ul>
<p>These restrictions were necessary. Imagine if any website you visited could silently read your documents or execute system commands. The browser sandbox kept users safe, but it also locked JavaScript into the client side.</p>
<h2>How Node.js Made JavaScript Run on Servers</h2>
<p>In 2009, a developer named Ryan Dahl asked a simple but revolutionary question: <em>What if we took JavaScript out of the browser and gave it access to the system?</em></p>
<p>He didn’t rewrite JavaScript. Instead, he took Google’s <strong>V8 JavaScript engine</strong> (the same one powering Chrome), extracted it from the browser, and wrapped it with C++ bindings. These bindings acted as a bridge, exposing operating-system-level features like:</p>
<ul>
<li><p>File system access (<code>fs</code> module)</p>
</li>
<li><p>Networking and HTTP servers (<code>net</code>, <code>http</code> modules)</p>
</li>
<li><p>Process management and environment variables</p>
</li>
<li><p>Cryptography and streams</p>
</li>
</ul>
<p>Suddenly, JavaScript wasn’t just manipulating DOM elements anymore. It could listen on port 3000, read a database, serve JSON, and handle thousands of concurrent requests. Node.js was born, and JavaScript became a full-stack language.</p>
<h2>The V8 Engine: A High-Level Overview</h2>
<p>You’ll often hear that Node.js is “fast,” and much of that credit goes to the <strong>V8 engine</strong>.</p>
<p>V8 is an open-source JavaScript engine written in C++ and developed by Google. Traditionally, scripting languages were interpreted line-by-line, which made them slow. V8 changed that by using <strong>Just-In-Time (JIT) compilation</strong>. Instead of reading JavaScript slowly during execution, V8 compiles it directly into optimized machine code that your CPU can run natively.</p>
<p>At a high level, V8:</p>
<ul>
<li><p>Parses your JavaScript code</p>
</li>
<li><p>Compiles it into fast machine code before/during execution</p>
</li>
<li><p>Optimizes hot code paths automatically</p>
</li>
<li><p>Handles memory management and garbage collection</p>
</li>
</ul>
<p>Node.js simply leverages V8’s speed and pairs it with system-level APIs. You write JavaScript, V8 makes it run fast, and Node.js gives it server capabilities.</p>
<h2>Event-Driven Architecture &amp; Non-Blocking I/O</h2>
<p>If V8 is the muscle, <strong>event-driven architecture</strong> is the nervous system of Node.js. This is where beginners often get confused, so let’s simplify it.</p>
<p>Traditional server languages often use a <strong>thread-per-request</strong> model. If 100 users make a request, the server spins up 100 threads. If one request waits for a database query, that thread sits idle, wasting memory and CPU.</p>
<p>Node.js works differently. It runs on a <strong>single thread</strong> but uses an <strong>event loop</strong> to handle tasks asynchronously. Here’s a real-world analogy:</p>
<p>Imagine a restaurant with one highly efficient waiter (the event loop). Instead of standing in the kitchen waiting for each dish to cook (blocking), the waiter takes an order, sends it to the kitchen, and immediately goes to serve other tables. When the food is ready, the kitchen rings a bell (an event), and the waiter delivers it. No waiting. No idle time.</p>
<p>In technical terms:</p>
<ul>
<li><p>I/O operations (database calls, file reads, network requests) are handed off to the system</p>
</li>
<li><p>Node.js continues executing other code</p>
</li>
<li><p>When the operation finishes, a callback or promise resolves, and the event loop picks it up</p>
</li>
<li><p>This is called <strong>non-blocking I/O</strong></p>
</li>
</ul>
<p>This architecture allows Node.js to handle tens of thousands of concurrent connections with minimal overhead, making it incredibly efficient for I/O-heavy workloads.</p>
<h2>Real-World Use Cases of Node.js</h2>
<p>Node.js isn’t a magic bullet for every problem, but it shines in specific scenarios. Here’s where it’s commonly used in production:</p>
<h3>1. Real-Time Applications</h3>
<p>Chat apps, live dashboards, collaborative editors (like Google Docs), and multiplayer games benefit from Node’s event-driven model. Technologies like WebSockets integrate seamlessly, enabling instant two-way communication.</p>
<h3>2. RESTful APIs &amp; Microservices</h3>
<p>Because JavaScript natively handles JSON, Node.js is a natural fit for building lightweight, fast APIs. Frameworks like Express.js make routing, middleware, and request handling straightforward. Many companies split monolithic apps into Node-powered microservices.</p>
<h3>3. Streaming Applications</h3>
<p>Node.js handles data streams efficiently. Instead of loading an entire file into memory, it processes data in chunks. This makes it ideal for video/audio streaming, large file uploads, and real-time data pipelines.</p>
<h3>4. Developer Tools &amp; CLI Utilities</h3>
<p>The npm (Node Package Manager) ecosystem hosts over a million packages. Tools like Webpack, ESLint, Vite, and countless CLI utilities are built with Node.js because it’s cross-platform, fast, and easy to distribute.</p>
<h3>5. Server-Side Rendering (SSR) &amp; Full-Stack Frameworks</h3>
<p>Modern frameworks like Next.js, Nuxt, and Remix use Node.js to render React/Vue components on the server, improving SEO and initial load performance before hydrating on the client.</p>
<h3>Where Node.js Isn’t Ideal</h3>
<p>It’s worth noting that Node.js struggles with <strong>CPU-intensive tasks</strong> like video encoding, image processing, or complex mathematical computations. Since it runs on a single thread, heavy CPU work can block the event loop. For those cases, languages like Python, Go, or Rust, or offloading to worker threads, are better choices.</p>
<h2>Conclusion</h2>
<p>Node.js didn’t just change where JavaScript could run; it changed how developers think about building web applications. By extracting the V8 engine from the browser, bridging it to system APIs, and embracing an event-driven, non-blocking architecture, Node.js turned a client-side scripting language into a server-side powerhouse.</p>
<p>If you’re just starting out, don’t worry about mastering every concept at once. Begin by running a simple <code>node app.js</code>, create a basic HTTP server, and watch how JavaScript behaves outside the browser. The more you experiment, the clearer the event loop, modules, and async patterns will become.</p>
<p>JavaScript was once confined to making buttons click. Today, thanks to Node.js, it powers APIs, real-time systems, and full-stack applications across the globe. And the best part? You already know the language. You just need the runtime.</p>
]]></content:encoded></item><item><title><![CDATA[Unlocking the Secrets of the Linux File System: A System Investigator's Journey]]></title><description><![CDATA[When you use a computer, you usually think of the file system as just a place to store your pictures, videos, and code files. But in Linux, the file system is much more than a storage box. It is the a]]></description><link>https://blog.suprabhat.site/linux-file-system</link><guid isPermaLink="true">https://blog.suprabhat.site/linux-file-system</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Linux]]></category><category><![CDATA[linux-file-system]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Wed, 22 Apr 2026 12:55:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/1445961c-b170-4278-812e-e55cb08ffce4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you use a computer, you usually think of the file system as just a place to store your pictures, videos, and code files. But in Linux, the file system is much more than a storage box. It is the actual control panel for the entire operating system. In Linux, there is a famous saying: Everything is a file. Your hard drive, your webcam, your active memory, and your network connections—they are all represented as files.</p>
<p>In this blog, we will step into the shoes of a system investigator. We will understand how Linux actually works under the hood by exploring its file system structure. We will dive into where user data lives, how the system talks to hardware, where DNS configurations hide, and how processes are managed.</p>
<p>First, let’s understand the central brain of the configuration: the <code>/etc</code> directory.</p>
<h3>1. The System’s Rulebook: <code>/etc/passwd</code> and <code>/etc/shadow</code></h3>
<p><strong>What it does:</strong> The <code>/etc</code> directory holds all the global configuration files for your system. Inside it, <code>/etc/passwd</code> lists all the registered users on the system, while <code>/etc/shadow</code> securely stores their encrypted passwords.</p>
<p><strong>Why it exists:</strong> Linux is a multi-user system. Imagine we want to create an account for a new developer, let's say, name: "Suprabhat", age: 23. Linux needs a centralized way to remember Suprabhat’s user ID, his default shell (like bash), and his home directory.</p>
<p><strong>What problem it solves:</strong> Without these files, the operating system wouldn’t know who is allowed to log in, what privileges they have, or where their files should be saved. It solves the problem of identity management.</p>
<p><strong>Interesting Insight:</strong> If you open <code>/etc/passwd</code>, you won't actually find any passwords! Years ago, passwords used to be stored there in plain sight. For security, Linux developers moved the passwords to <code>/etc/shadow</code>, which can only be read by the root user (the super admin). <code>/etc/passwd</code> remains readable by everyone so applications know who exists on the system, but the actual security key is hidden away.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/d1a53e22-7b39-4b44-a0a9-4ee2aadf4ecc.png" alt="/etc/passwd and /etc/shadow In Linux." style="display:block;margin:0 auto" />

<h3>2. The Illusion of Files: <code>/proc</code> (The Process Information Pseudo-file System)</h3>
<p><strong>What it does:</strong> The <code>/proc</code> directory contains directories and files that act as a window into the core of the Linux kernel and running processes. For example, <code>/proc/cpuinfo</code> shows details about your processor, and <code>/proc/meminfo</code> shows your RAM usage.</p>
<p><strong>Why it exists:</strong> When you open a Task Manager on Windows, it shows you running apps. In Linux, the system needs a way to expose what the CPU and memory are doing in real-time without requiring complex programming.</p>
<p><strong>What problem it solves:</strong> It bridges the gap between the kernel (the core of the OS) and user applications. It allows tools to monitor system health simply by reading text files.</p>
<p><strong>Interesting Insight:</strong> <code>/proc</code> is completely fake! It is a "pseudo-file system." It doesn’t exist on your hard drive at all. It is generated dynamically in your RAM by the kernel. When you read a file inside <code>/proc</code>, you are actually querying the kernel directly at that exact millisecond. If you reboot, <code>/proc</code> is completely wiped and rebuilt.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/2e69c187-ce33-4d57-b74e-1b5ede259e29.png" alt="/proc (The Process Information Pseudo-file System)" style="display:block;margin:0 auto" />

<h3>3. Where Hardware Meets Software: The <code>/dev</code> Directory</h3>
<p><strong>What it does:</strong> This directory contains "device files." Every piece of hardware attached to your computer, your hard disk (<code>/dev/sda</code>), your webcam (<code>/dev/video0</code>), or your mouse, has a corresponding file here.</p>
<p><strong>Why it exists:</strong> Linux applications don’t want to write complicated code to talk to different brands of hard drives or webcams. By turning hardware into files, Linux makes life easy for developers.</p>
<p><strong>What problem it solves:</strong> It standardizes hardware interaction. To send data to a device, a program just "writes" to that device's file. To read from a microphone, a program just "reads" from the microphone's file.</p>
<p><strong>Interesting Insight:</strong> There is a famous file here called <code>/dev/null</code>. It is the system's "black hole." If you have a program that generates a lot of annoying error messages and you want to silence them, you can route the output to <code>/dev/null</code>. Anything sent there is instantly destroyed and discarded.</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/2d77fa98-ef35-4624-a929-1a537291bb56.png" alt="/dev Directory in Linux." style="display:block;margin:0 auto" />

<h3>4. The Internet’s Compass: <code>/etc/resolv.conf</code></h3>
<p><strong>What it does:</strong> This file tells your Linux system which DNS (Domain Name System) servers to use when converting human-readable websites (like google.com) into computer-readable IP addresses.</p>
<p><strong>Why it exists:</strong> When you open a web browser and type a URL, your computer has to ask someone, "Where is this website?" <code>/etc/resolv.conf</code> contains the IP addresses of the servers it should ask.</p>
<p><strong>What problem it solves:</strong> It provides the system with a critical roadmap for internet navigation. Without it, your system wouldn't know how to resolve domain names, and the internet would seem completely broken unless you memorized IP addresses.</p>
<p><strong>Interesting Insight:</strong> If you manually edit this file to add a fast DNS server (like Google's <code>8.8.8.8</code>), you might be surprised to find your changes erased after a reboot! This is because modern Linux systems use background services (like NetworkManager or systemd-resolved) that automatically overwrite <code>/etc/resolv.conf</code> based on the network you just connected to (like a coffee shop Wi-Fi).</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/9809ee2f-ebfb-49b0-baf1-0f4ff5ba6606.png" alt="/etc/resolv.conf  In Linux." style="display:block;margin:0 auto" />

<h3>5. The System’s Diary: <code>/var/log</code></h3>
<p><strong>What it does:</strong> The <code>/var/log</code> directory is where Linux keeps its journals. Every time someone logs in, every time a web server crashes, and every time the system boots up, a note is written here.</p>
<p><strong>Why it exists:</strong> Computers do millions of things in the background. If something goes wrong, administrators need a paper trail to figure out what happened.</p>
<p><strong>What problem it solves:</strong> It solves the problem of blind troubleshooting. Instead of guessing why a server crashed at 3:00 AM, you can read the logs to see exactly what happened at 2:59 AM.</p>
<p><strong>Interesting Insight:</strong> If you manage a public-facing Linux server and look inside <code>/var/log/auth.log</code> (or <code>/var/log/secure</code> depending on your Linux version), you will likely see hundreds of failed login attempts from unknown IP addresses all over the world. These are automated bots trying to guess your passwords. Seeing this in real-time is a powerful reminder of why we use strong passwords and SSH keys!</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/f3c8130e-f4ae-4458-a292-9ef6a36e7400.png" alt="/var/log  In Linux." style="display:block;margin:0 auto" />

<h3>6. The Heartbeat of Background Tasks: <code>/etc/systemd/system/</code></h3>
<p><strong>What it does:</strong> This directory contains configuration files (called "unit files") that dictate how background services, like web servers, databases, or network managers, should start, stop, and behave.</p>
<p><strong>Why it exists:</strong> When you turn on your computer, you don’t want to manually type commands to start your database, your web server, and your firewall. You want them to start automatically.</p>
<p><strong>What problem it solves:</strong> It provides a structured, automated way to manage the lifecycle of software. If a web server crashes, systemd can look at its configuration file here and know exactly how to restart it automatically.</p>
<p><strong>Interesting Insight:</strong> You can create your own custom service in minutes. If you write a simple Python script and want it to run forever in the background, you just create a <code>.service</code> file here, tell systemd where your script is, and Linux will treat your script with the same respect and priority as enterprise-level databases!</p>
<img src="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/1baf4f6c-6714-4439-887d-b10158d06094.png" alt="/etc/systemd/system/ In Linux." style="display:block;margin:0 auto" />

<h3>Conclusion</h3>
<p>Linux is not a black box; it is an open book if you know which pages to turn. By exploring directories like <code>/etc</code> for configurations, <code>/proc</code> for active memory state, <code>/dev</code> for hardware, and <code>/var/log</code> for history, you move from being just a "user" to a true system investigator.</p>
<p>Understanding this file structure helps you see exactly how data is managed, how security is enforced, and how the operating system talks to the physical machine behind the scenes. The next time you are on a Linux terminal, don't just stay in your home folder, take a walk through the root directory and see what secrets you can uncover!</p>
]]></content:encoded></item><item><title><![CDATA[Map and Set in JavaScript]]></title><description><![CDATA[Whenever you need to store data in JavaScript, what is the first thing that comes to your mind? If you have a list of items, you probably use an Array. If you have data with labels (key-value pairs), ]]></description><link>https://blog.suprabhat.site/map-and-set-in-javascript</link><guid isPermaLink="true">https://blog.suprabhat.site/map-and-set-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[ChaiCohort]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[map]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sun, 19 Apr 2026 14:48:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/97571b37-7a94-47c1-a241-a952de30bb5c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whenever you need to store data in JavaScript, what is the first thing that comes to your mind? If you have a list of items, you probably use an <strong>Array</strong>. If you have data with labels (key-value pairs), you probably use an <strong>Object</strong>.</p>
<p>For years, Arrays and Objects were the only tools developers had to organize data. But as web applications became more complex, developers started running into frustrating limitations.</p>
<p>To solve these problems, JavaScript introduced two powerful new data structures in ES6: <strong>Map</strong> and <strong>Set</strong>.</p>
<p>In this blog, we will explore the problems with traditional Objects and Arrays, what Map and Set are, how they differ from their older counterparts, and exactly when you should use them in your own code.</p>
<h3>The Problem with Traditional Objects and Arrays</h3>
<p>Before we look at the solutions, we need to understand the problems.</p>
<p><strong>The Array Problem:</strong> Arrays are fantastic for keeping a list of items in a specific order. However, arrays allow duplicate values. If you are building a social media app and want to keep a list of unique users who liked a post, an Array will happily let the same user be added 10 times. To prevent this, you have to write extra loops and conditional logic to check if a user already exists before adding them.</p>
<p><strong>The Object Problem:</strong> Objects are the traditional way to store key-value data, like a user profile where <code>name: "Suprabhat", age: 23</code>. But Objects have a massive hidden flaw: <strong>Object keys can only be Strings or Symbols.</strong> If you try to use a number, a boolean, or even another object as a key, JavaScript will automatically convert it into a string. This can cause bizarre bugs and limits how you can organize complex data.</p>
<p>Let's see how Map and Set rescue us from these issues.</p>
<h3>What is a Set?</h3>
<p>A <strong>Set</strong> is a special type of collection that holds a list of values, just like an Array. But it has one strict, magical rule: <strong>Every value in a Set must be 100% unique.</strong></p>
<p>You can never have duplicates in a Set. If you try to add a value that already exists, the Set simply ignores it. This "uniqueness property" makes Sets incredibly useful for filtering data.</p>
<p>Let's look at how easy it is to use a Set:</p>
<pre><code class="language-javascript">// Creating a new Set
const uniqueTags = new Set();

// Adding values
uniqueTags.add("javascript");
uniqueTags.add("web");
uniqueTags.add("javascript"); // This is a duplicate!

console.log(uniqueTags); 
// Output: Set(2) { 'javascript', 'web' }
</code></pre>
<p>Notice how we tried to add "javascript" twice, but the Set only kept one copy.</p>
<p>A very common developer trick is to pass an Array with duplicates directly into a Set to instantly clean it up:</p>
<pre><code class="language-javascript">const messyArray = [1, 2, 2, 3, 3, 3, 4];
const cleanSet = new Set(messyArray);

console.log(cleanSet); // Output: Set(4) { 1, 2, 3, 4 }
</code></pre>
<h3>Difference between Set and Array</h3>
<p>While they look similar, they serve very different purposes.</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Array</th>
<th>Set</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Duplicates</strong></td>
<td>Allowed.</td>
<td>Strictly NOT allowed (Unique only).</td>
</tr>
<tr>
<td><strong>Data Access</strong></td>
<td>Accessed by index position (e.g., <code>myArray[0]</code>).</td>
<td>No index. You check if a value exists using <code>mySet.has(value)</code>.</td>
</tr>
<tr>
<td><strong>Performance</strong></td>
<td>Searching for an item is slower in large lists.</td>
<td>Checking if an item exists is incredibly fast.</td>
</tr>
<tr>
<td><strong>Best For</strong></td>
<td>Ordered data where position matters.</td>
<td>Storing unique values and checking for their existence.</td>
</tr>
</tbody></table>
<h3>What is a Map?</h3>
<p>A <strong>Map</strong> is a collection of keyed data items, just like an Object. It holds key-value pairs.</p>
<p>However, Map completely solves the biggest problem with Objects: <strong>A Map allows keys of ANY data type.</strong> Your key can be a string, a number, a boolean, a function, or even an entire object!</p>
<p>Let's look at an example. Imagine we want to store extra information about a specific user object without actually modifying the original object.</p>
<pre><code class="language-javascript">// Our traditional user object
const user1 = { name: "Suprabhat", age: 23 };

// Creating a new Map
const userRoles = new Map();

// We are using the ENTIRE user object as the key!
userRoles.set(user1, "Admin");

console.log(userRoles.get(user1)); // Output: "Admin"
</code></pre>
<p>If we tried to do this with a regular Object, JavaScript would convert the <code>user1</code> object into a useless string <code>"[object Object]"</code>. With Map, the original object is preserved securely as the key.</p>
<p>Additionally, Maps have built-in features that make them easier to work with, such as a <code>.size</code> property that instantly tells you how many items are inside (unlike Objects, where you have to manually count the keys).</p>
<h3>Difference between Map and Object</h3>
<p>Here is a quick comparison to help you choose the right tool for key-value storage.</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Object</th>
<th>Map</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Key Types</strong></td>
<td>Must be Strings or Symbols.</td>
<td>Can be absolutely anything (Objects, Arrays, Numbers).</td>
</tr>
<tr>
<td><strong>Order of Items</strong></td>
<td>Not guaranteed to be in the order you added them.</td>
<td>Strictly remembers the exact order of insertion.</td>
</tr>
<tr>
<td><strong>Getting Size</strong></td>
<td>Difficult. You must use <code>Object.keys(obj).length</code>.</td>
<td>Easy. Just use the built-in <code>myMap.size</code> property.</td>
</tr>
<tr>
<td><strong>Iteration</strong></td>
<td>Requires extra methods like <code>Object.entries()</code>.</td>
<td>Built natively for iteration using loops like <code>for...of</code>.</td>
</tr>
</tbody></table>
<h3>When to use Map and Set</h3>
<p>Now that we know how they work, when should you actually use them in your daily coding?</p>
<p><strong>When to use Set:</strong></p>
<ul>
<li><p><strong>Removing Duplicates:</strong> Whenever you receive messy data (like user inputs or database results) and need to ensure there are no repeating values.</p>
</li>
<li><p><strong>Fast Lookups:</strong> If you have a massive list of ID numbers and you need to constantly check if a specific ID exists, using <code>mySet.has(id)</code> is much faster than searching through an Array.</p>
</li>
<li><p><strong>Managing States:</strong> Keeping track of things that are either "on" or "off" (like a list of currently selected checkboxes).</p>
</li>
</ul>
<p><strong>When to use Map:</strong></p>
<ul>
<li><p><strong>Complex Keys:</strong> When you need to associate data with a DOM element or another Object without modifying the original object.</p>
</li>
<li><p><strong>Frequent Updates:</strong> Maps are highly optimized for scenarios where you are constantly adding and removing key-value pairs.</p>
</li>
<li><p><strong>Predictable Iteration:</strong> When you need to loop through key-value data and absolutely need the items to appear in the exact order you added them.</p>
</li>
</ul>
<h3>Conclusion</h3>
<p>Arrays and Objects will always be the foundational building blocks of JavaScript. You will still use them every single day.</p>
<p>However, <code>Map</code> and <code>Set</code> are highly specialized tools built for modern development. By understanding that <strong>Set</strong> is your go-to for guaranteed unique lists, and <strong>Map</strong> is your heavy-duty key-value storage that accepts any data type, you will write cleaner, faster, and much less buggy code.</p>
]]></content:encoded></item><item><title><![CDATA[JavaScript Promises Explained]]></title><description><![CDATA[Imagine you walk into a busy fast-food restaurant and order a burger. The cashier takes your money, but they don't hand you a burger immediately. Instead, they give you a receipt with an order number.]]></description><link>https://blog.suprabhat.site/javascript-promises-explained</link><guid isPermaLink="true">https://blog.suprabhat.site/javascript-promises-explained</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[promises]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sun, 19 Apr 2026 14:44:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/97a58d4e-db0b-4ad7-b384-40cc384797fc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine you walk into a busy fast-food restaurant and order a burger. The cashier takes your money, but they don't hand you a burger immediately. Instead, they give you a receipt with an order number.</p>
<p>That receipt is not your food, but it is a <strong>promise</strong> that you will get your food in the future. While you wait, you don't have to freeze in place; you can go fill your drink, find a table, or talk to your friends. Eventually, your number is called, and you either get your delicious burger, or the cashier apologizes and says they ran out of ingredients.</p>
<p>In JavaScript, we deal with things that take time, like fetching user data from a server or downloading an image. To handle these time-consuming tasks without freezing the entire website, JavaScript uses exactly this concept: <strong>Promises</strong>.</p>
<p>In this blog, we will understand what problem promises solve, what a promise actually is, the three states of a promise's lifecycle, how to handle success and failure, and how promise chaining makes our code incredibly easy to read.</p>
<p>First, let’s understand the mess we used to live in before Promises existed.</p>
<h3>The Problem Promises Solve</h3>
<p>Before promises were introduced, JavaScript handled time-consuming tasks using <strong>callbacks</strong>. A callback is simply a function passed into another function, designed to run only when the task is finished.</p>
<p>For one simple task, a callback is fine. But what if you have a sequence of tasks that depend on each other?</p>
<ol>
<li><p>Fetch the user's profile.</p>
</li>
<li><p>Using that profile, fetch their recent posts.</p>
</li>
<li><p>Using the posts, fetch the comments.</p>
</li>
</ol>
<p>Using callbacks, your code would look like this:</p>
<pre><code class="language-javascript">getUserProfile(function(profile) {
    getRecentPosts(profile.id, function(posts) {
        getComments(posts[0].id, function(comments) {
            displayComments(comments);
        });
    });
});
</code></pre>
<p>Developers affectionately call this <strong>"Callback Hell"</strong> or the <strong>"Pyramid of Doom."</strong> The code keeps moving further and further to the right. It becomes incredibly difficult to read, nearly impossible to debug, and handling errors (like a network failure at step 2) turns into an absolute nightmare.</p>
<p>Promises were created to solve this exact problem. They flatten out the code, vastly improving readability and making error handling a breeze.</p>
<h3>What is a Promise? (The Lifecycle and States)</h3>
<p>Conceptually, a Promise in JavaScript is exactly like your restaurant receipt. It is an object that represents a <strong>future value</strong>, a value that is not available right now, but will be resolved at some point later.</p>
<p>Every promise goes through a strict lifecycle and will always be in one of these three <strong>states</strong>:</p>
<ol>
<li><p><strong>Pending:</strong> This is the initial state. The order has been placed, but the burger is not ready yet. The promise is waiting for the background task to finish.</p>
</li>
<li><p><strong>Fulfilled (Resolved):</strong> The task completed successfully. Your number was called, and you got your burger. The promise now holds the final data you requested.</p>
</li>
<li><p><strong>Rejected:</strong> The task failed. The restaurant ran out of ingredients, or your internet disconnected. The promise now holds an error message explaining what went wrong.</p>
</li>
</ol>
<p>Once a promise becomes <em><strong>Fulfilled</strong></em> or <em><strong>Rejected</strong></em>, we say it is <strong>"settled."</strong> A settled promise can never change its state again.</p>
<h3>Handling Success and Failure</h3>
<p>When a JavaScript function gives you a promise, you need a way to say: <em>"When this is finally ready, do this. If it fails, do that."</em></p>
<p>We handle this using two built-in methods: <code>.then()</code> and <code>.catch()</code>.</p>
<ul>
<li><p><code>.then()</code> runs only if the promise is <strong>Fulfilled</strong>.</p>
</li>
<li><p><code>.catch()</code> runs only if the promise is <strong>Rejected</strong>.</p>
</li>
</ul>
<p>Let's look at how we would handle our restaurant order in code:</p>
<pre><code class="language-javascript">orderBurger()
    .then(function(myBurger) {
        // This runs if the promise is FULFILLED
        console.log("Yum! I am eating my " + myBurger);
    })
    .catch(function(errorMsg) {
        // This runs if the promise is REJECTED
        console.log("Oh no: " + errorMsg);
    });
</code></pre>
<p>It reads almost exactly like plain English. <em>Order the burger, then eat it, or catch the error.</em> You don't have to pass complex functions deep inside other functions anymore.</p>
<h3>The Promise Chaining Concept</h3>
<p>The true superpower of promises is <strong>Chaining</strong>.</p>
<p>Remember the dreadful Callback Hell we looked at earlier? Because every <code>.then()</code> method actually returns a <em>brand new promise</em>, we can chain multiple <code>.then()</code> blocks together. This completely eliminates the Pyramid of Doom.</p>
<p>Let's rewrite that ugly callback code using promise chaining:</p>
<pre><code class="language-javascript">getUserProfile()
    .then(function(profile) {
        return getRecentPosts(profile.id);
    })
    .then(function(posts) {
        return getComments(posts[0].id);
    })
    .then(function(comments) {
        displayComments(comments);
    })
    .catch(function(error) {
        console.log("Something went wrong at one of the steps: " + error);
    });
</code></pre>
<p>Look at how beautifully this code flows! Instead of moving diagonally to the right, it reads perfectly from <strong>top to bottom</strong>.</p>
<p>Even better, we only need <strong>one single</strong> <code>.catch()</code> at the very bottom. If <code>getUserProfile</code> fails, or <code>getRecentPosts</code> fails, or <code>getComments</code> fails, JavaScript will automatically skip the remaining <code>.then()</code> blocks and jump straight down to the <code>.catch()</code>. This makes error handling incredibly clean and centralized.</p>
<h3>Conclusion</h3>
<p>Promises modernized the way developers write JavaScript. By treating asynchronous operations as a "future value" rather than a messy web of callbacks, our code becomes much more predictable.</p>
<p>Understanding the three states, pending, fulfilled, and rejected, gives you a mental model for how data flows over time. And by mastering <code>.then()</code> and <code>.catch()</code> chains, you can write complex, multi-step network requests that are as easy to read as a simple list of instructions.</p>
<p>The next time you write a network request, remember the restaurant receipt: you are just waiting for a promise to settle!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding the this Keyword in JavaScript]]></title><description><![CDATA[If you ask any JavaScript developer what the most confusing part of the language is, there is a very high chance they will say the this keyword. It is famous for causing headaches, breaking code, and ]]></description><link>https://blog.suprabhat.site/understanding-the-this-keyword-in-javascript</link><guid isPermaLink="true">https://blog.suprabhat.site/understanding-the-this-keyword-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[this keyword]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sun, 19 Apr 2026 14:37:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/e81ac257-e029-4ba8-b41a-5c499279c563.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you ask any JavaScript developer what the most confusing part of the language is, there is a very high chance they will say the <code>this</code> keyword. It is famous for causing headaches, breaking code, and popping up as a trick question in almost every technical interview.</p>
<p>But the truth is, <code>this</code> is not actively trying to trick you. It just follows a very strict set of rules.</p>
<p>In this blog, we are going to decode those rules. We will explore what <code>this</code> actually represents, how it behaves in the global scope, inside objects, and inside regular functions. Most importantly, we will learn the golden rule for figuring out exactly what <code>this</code> is pointing to in any situation.</p>
<p>Let’s start with the most basic question.</p>
<h3>What <code>this</code> Represents</h3>
<p>To understand <code>this</code> in JavaScript, think about how we use pronouns in the English language.</p>
<p>Imagine reading this sentence: <em>"Suprabhat bought a new laptop, and</em> <em><strong>he</strong></em> <em>loves it."</em> You immediately know that "he" refers to Suprabhat. You don't need to repeat his name.</p>
<p>In JavaScript, <code>this</code> is exactly like that pronoun. It is a shortcut reference to an object. But which object?</p>
<p>Here is the ultimate secret to understanding <code>this</code>: <code>this</code> <strong>is simply the object that is calling the function right now.</strong> It does not matter where the function was written, or when it was created. The <em>only</em> thing that matters is <strong>how</strong> and <strong>who</strong> is executing the function at the exact moment it runs.</p>
<h3><code>this</code> in the Global Context</h3>
<p>Let's start by looking at <code>this</code> completely on its own, outside of any functions or custom objects.</p>
<p>If you open your browser's developer console and simply type:</p>
<pre><code class="language-javascript">console.log(this);
</code></pre>
<p>What do you get? You will see the global <code>window</code> object.</p>
<p>In a browser environment, the <code>window</code> object is the massive parent object that holds everything together (like your screen width, your browsing history, and built-in tools like <code>alert()</code>). When you use <code>this</code> in the open global space, JavaScript assumes you are talking about the biggest object in the room: the global window.</p>
<h3><code>this</code> Inside Objects</h3>
<p>The most common place you will use <code>this</code> is inside an object's method. A method is just a function that belongs to an object.</p>
<p>Let's create a profile for a user:</p>
<pre><code class="language-javascript">const user = {
    name: "Suprabhat",
    age: 23,
    greet: function() {
        console.log("Hello! My name is " + this.name);
    }
};

user.greet(); // Output: Hello! My name is Suprabhat
</code></pre>
<p>Why did this work perfectly? Let's apply our secret rule: <em>Who is calling the function?</em></p>
<p>Look at the line where we execute the code: <code>user.greet()</code>. Notice what is to the <strong>left of the dot</strong>. It is the <code>user</code> object. Because the <code>user</code> object is the one calling the <code>greet</code> function, JavaScript temporarily points the <code>this</code> pronoun directly to <code>user</code>. Therefore, <code>this.name</code> translates perfectly to <code>user.name</code>.</p>
<h3><code>this</code> Inside Regular Functions</h3>
<p>Things start to get a little weird when we use <code>this</code> inside a normal function that is <em>not</em> attached to an object.</p>
<pre><code class="language-javascript">function showThis() {
    console.log(this);
}

showThis();
</code></pre>
<p>If you run this code, what will be printed?</p>
<p>Again, ask the golden question: <em>Who is calling the function?</em> When you just call <code>showThis()</code> by itself, there is no object to the left of a dot. It is just floating out in the global space. Because of this, JavaScript defaults to the global environment. The output will once again be the global <code>window</code> object!</p>
<blockquote>
<p><strong>A Quick Note on Strict Mode:</strong> Because defaulting to the massive <code>window</code> object can cause accidental bugs, modern JavaScript introduced "strict mode" (<code>"use strict";</code>). If you are using strict mode, JavaScript will refuse to default to the window object. Instead, <code>this</code> inside a regular floating function will simply be <code>undefined</code>.</p>
</blockquote>
<h3>How Calling Context Changes <code>this</code></h3>
<p>This is the exact concept that interviewers love to test you on. You now know that <code>this</code> depends entirely on how a function is called. Let's see how easily we can accidentally break <code>this</code> by changing the caller.</p>
<p>Let's use our <code>user</code> object again:</p>
<pre><code class="language-javascript">const user = {
    name: "Suprabhat",
    age: 23,
    greet: function() {
        console.log("Hello! My name is " + this.name);
    }
};

// We assign the function to a brand new variable
const floatingGreeting = user.greet;

// Now, we call the new variable
floatingGreeting(); 
</code></pre>
<p><strong>Output: "Hello! My name is undefined"</strong></p>
<p>Wait, what happened? The function is the exact same code! Why did it lose the name?</p>
<p>Let's trace the execution:</p>
<ol>
<li><p>We took the <code>greet</code> function out of the <code>user</code> object and stored it in a new, independent variable called <code>floatingGreeting</code>.</p>
</li>
<li><p>We executed <code>floatingGreeting()</code>.</p>
</li>
<li><p><em>Who is calling the function?</em> Look to the left of the parenthesis. There is no dot! There is no object!</p>
</li>
</ol>
<p>Because <code>floatingGreeting()</code> was called as a regular, floating function in the global space, <code>this</code> stopped pointing to <code>user</code> and started pointing to the global <code>window</code> object. Since the global window does not have a property called <code>name</code>, <code>this.name</code> evaluates to <code>undefined</code>.</p>
<p>This proves our golden rule: <code>this</code> <strong>is not tied to where a function is written. It is entirely tied to the object calling it at the moment of execution.</strong></p>
<h3>Conclusion</h3>
<p>The <code>this</code> keyword does not have to be intimidating. It is simply a dynamic pronoun that changes based on who is speaking.</p>
<p>If you ever get stuck trying to figure out what <code>this</code> represents in your code, don't panic. Just look for where the function is actually being executed with parentheses <code>()</code>.</p>
<ul>
<li><p><strong>If there is an object to the left of the dot</strong> (e.g., <code>myObject.myFunction()</code>), <code>this</code> is that object.</p>
</li>
<li><p><strong>If there is no dot</strong> (e.g., <code>myFunction()</code>), <code>this</code> is the global window (or <code>undefined</code> in strict mode).</p>
</li>
</ul>
<p>By shifting your focus away from where the code was written and focusing entirely on <em>how</em> it is called, the mystery of the <code>this</code> keyword completely disappears.</p>
]]></content:encoded></item><item><title><![CDATA[The new Keyword in JavaScript]]></title><description><![CDATA[Imagine you are building a brand new social media application. Your first task is to create user profiles. If you only have one user, creating their profile in JavaScript is incredibly easy. You just ]]></description><link>https://blog.suprabhat.site/the-new-keyword-in-javascript</link><guid isPermaLink="true">https://blog.suprabhat.site/the-new-keyword-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[new keyword]]></category><dc:creator><![CDATA[SUPRABHAT]]></dc:creator><pubDate>Sun, 19 Apr 2026 14:33:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/67878f19cf0699455cef774d/3115c190-2fd9-461a-8e0b-d697954157f1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine you are building a brand new social media application. Your first task is to create user profiles. If you only have one user, creating their profile in JavaScript is incredibly easy. You just write a simple object:</p>
<pre><code class="language-javascript">const user1 = {
    name: "Suprabhat",
    age: 23,
    isOnline: true
};
</code></pre>
<p>But what happens when your app goes viral and you suddenly have ten thousand users? Manually typing out an object for every single person is impossible. You need a factory, a reusable blueprint that can stamp out new user profiles on demand, ensuring they all have the exact same structure.</p>
<p>In JavaScript, we build these blueprints using <strong>Constructor Functions</strong>, and we bring them to life using the <code>new</code> keyword.</p>
<p>In this blog, we will completely demystify object creation in JavaScript. We will understand what constructor functions are, the exact step-by-step magic the <code>new</code> keyword performs behind the scenes, how prototypes are linked, and what it means to be an "instance."</p>
<p>First, let’s understand the blueprint itself: the Constructor Function.</p>
<h3>What are Constructor Functions?</h3>
<p>A constructor function is essentially a regular JavaScript function, but it is written with a specific purpose: <strong>to build and initialize new objects.</strong> To distinguish constructor functions from normal functions, developers follow a strict naming convention. We always capitalize the first letter of a constructor function's name.</p>
<p>Here is a simple example of a constructor function for our social media app:</p>
<pre><code class="language-javascript">function User(name, age) {
    this.name = name;
    this.age = age;
    this.isOnline = false;
}
</code></pre>
<p>Looking at this code, you might be wondering: <em>What is</em> <code>this</code><em>? And how does this function actually give me an object? It doesn't even have a</em> <code>return</code> <em>statement!</em></p>
<p>If you try to call this function normally by writing <code>User("Suprabhat", 23)</code>, it will actually fail to create an object. In strict mode, it will throw an error, and in non-strict mode, it will accidentally attach the <code>name</code> and <code>age</code> variables to your global browser window.</p>
<p>To make this factory work, we need a special tool. We need the <code>new</code> keyword.</p>
<h3>What the <code>new</code> Keyword Does</h3>
<p>The <code>new</code> keyword is an operator in JavaScript that completely changes how a function behaves. When you place <code>new</code> in front of a function call, you are telling JavaScript: <em>"Do not run this like a normal function. Run this as an object factory."</em></p>
<p>Let's use it to create our user:</p>
<pre><code class="language-javascript">const myUser = new User("Suprabhat", 23);
console.log(myUser.name); // Output: Suprabhat
</code></pre>
<p>By simply adding <code>new</code>, the function magically creates an object, assigns the properties, and returns it to us. But there is no actual "magic" in programming. The <code>new</code> keyword executes a very specific, hardcoded sequence of events every single time it is used.</p>
<h3>The Object Creation Process (Step-by-Step)</h3>
<p>When you type <code>new User("Suprabhat", 23)</code>, JavaScript immediately pauses your code and secretly performs <strong>four crucial steps</strong> behind the scenes. Understanding these four steps is one of the most important concepts for JavaScript technical interviews.</p>
<p><strong>Step 1: A brand new, empty object is created.</strong> The very first thing <code>new</code> does is create a blank JavaScript object out of thin air: <code>{}</code>.</p>
<p><strong>Step 2: The</strong> <code>this</code> <strong>keyword is pointed to the new object.</strong> In our <code>User</code> function, we wrote <code>this.name = name;</code>. Because we used <code>new</code>, JavaScript takes the empty object from Step 1 and binds the <code>this</code> keyword to it. So, when the function says <code>this.name = "Suprabhat"</code>, it is actually saying: <em>"Inside this new empty object, create a property called name and set it to Suprabhat."</em></p>
<p><strong>Step 3: The new object is linked to the constructor's prototype.</strong> This is the most powerful step. JavaScript takes the newly created object and secretly links its hidden internal <code>[[Prototype]]</code> property to the <code>User.prototype</code> object. (We will explore why this is so important in the next section).</p>
<p><strong>Step 4: The new object is automatically returned.</strong> Notice how our <code>User</code> function did not have a <code>return</code> keyword? Because we used <code>new</code>, JavaScript automatically says: <em>"The function is done running, I will now return the object we just built."</em> If we were to write out what <code>new</code> does manually, it looks conceptually like this:</p>
<pre><code class="language-javascript">// What 'new User("Suprabhat", 23)' does behind the scenes:
function User(name, age) {
    // Step 1 &amp; 2: Secretly creates an object and points 'this' to it
    // this = {}; 

    // Step 3: Secretly links the prototype
    // Object.setPrototypeOf(this, User.prototype);

    this.name = name;
    this.age = age;
    this.isOnline = false;

    // Step 4: Secretly returns the object
    // return this;
}
</code></pre>
<h3>How <code>new</code> Links Prototypes (And Why It Matters)</h3>
<p>Imagine you want every user in your app to have a <code>login()</code> function. You <em>could</em> write it inside the constructor like this:</p>
<pre><code class="language-javascript">function User(name, age) {
    this.name = name;
    this.age = age;
    this.login = function() {
        console.log(this.name + " has logged in.");
    };
}
</code></pre>
<p>This works perfectly fine, but there is a massive hidden problem: <strong>Memory Waste.</strong></p>
<p>If you create 10,000 users using <code>new User()</code>, JavaScript will create 10,000 completely separate copies of the <code>login</code> function. Every single object will carry its own heavy backpack with the exact same function inside. This will severely slow down your application.</p>
<p>This is where <strong>Step 3</strong> of the <code>new</code> keyword (linking the prototype) saves the day.</p>
<p>Instead of putting the function inside the constructor, we put it on the constructor's <strong>Prototype</strong>. You can think of the prototype as a shared toolshed.</p>
<pre><code class="language-javascript">function User(name, age) {
    this.name = name;
    this.age = age;
}

// We put the tool in the shared toolshed
User.prototype.login = function() {
    console.log(this.name + " has logged in.");
};

const userA = new User("Suprabhat", 23);
const userB = new User("Alex", 30);

userA.login(); // Output: Suprabhat has logged in.
userB.login(); // Output: Alex has logged in.
</code></pre>
<p>Because the <code>new</code> keyword automatically links <code>userA</code> and <code>userB</code> to the <code>User.prototype</code> (the shared toolshed), they can both use the <code>login</code> function whenever they want, even though they don't directly own it! We now have 10,000 users, but only <strong>one</strong> copy of the <code>login</code> function in memory.</p>
<h3>Instances Created from Constructors</h3>
<p>Once an object is successfully created by a constructor using the <code>new</code> keyword, we give it a special name. We do not just call it an "object" we call it an <strong>Instance</strong>.</p>
<p>In our example, <code>userA</code> is an <em>instance</em> of <code>User</code>.</p>
<p>JavaScript provides a very handy built-in operator called <code>instanceof</code> to verify where an object came from. This is incredibly useful when you are debugging complex code and need to know which blueprint created a specific object.</p>
<pre><code class="language-javascript">console.log(userA instanceof User); // Output: true
console.log(userA instanceof Array); // Output: false
</code></pre>
<p>Because <code>userA</code> was created by <code>new User()</code>, and its prototype is linked to <code>User.prototype</code>, JavaScript confidently tells us that <code>true</code>, this object is indeed an instance of your <code>User</code> blueprint.</p>
<h3>Conclusion</h3>
<p>Object creation is the beating heart of JavaScript. The <code>new</code> keyword might look like a simple, three-letter word, but it is responsible for the heavy lifting of modern web development.</p>
<p>By understanding that <code>new</code> creates an empty object, points the <code>this</code> keyword, links the shared prototype toolshed, and automatically returns the finished product, you are no longer just guessing how JavaScript works. You understand the exact mechanics behind the scenes.</p>
<p>Constructor functions and prototypes ensure that whether your application has one user or one million, your code remains clean, efficient, and highly scalable.</p>
]]></content:encoded></item></channel></rss>