<?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[Strnge Blogs]]></title><description><![CDATA[Strnge | ishav.space & ishavthinks.com — Dev blogs, finance insights, life musings. Learn Next.js, React, Tailwind & growth strategies with Strnge.]]></description><link>https://blogs.ishav.space</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1707312203149/R67dMdzmY.png</url><title>Strnge Blogs</title><link>https://blogs.ishav.space</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 08 Jun 2026 01:29:41 GMT</lastBuildDate><atom:link href="https://blogs.ishav.space/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[🚀 Supercharge Your App with Google Apps Script + Google Sheets Integration]]></title><description><![CDATA[If you’re building modern web applications, chances are you’ve needed a simple backend for tasks like storing form submissions, feedback requests, or lightweight data logs. Instead of spinning up a server or managing databases, what if you could just...]]></description><link>https://blogs.ishav.space/supercharge-app-google-apps-script-sheets</link><guid isPermaLink="true">https://blogs.ishav.space/supercharge-app-google-apps-script-sheets</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Google]]></category><category><![CDATA[google sheets]]></category><category><![CDATA[backend]]></category><category><![CDATA[mvp]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sat, 31 May 2025 15:35:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748707253605/221bee1e-01c6-44d6-9fcd-66bf54f45f3f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’re building modern web applications, chances are you’ve needed a simple backend for tasks like storing form submissions, feedback requests, or lightweight data logs. Instead of spinning up a server or managing databases, what if you could just use <strong>Google Sheets as your backend</strong>? Enter <strong>Google Apps Script (GAS)</strong>—your secret weapon for lightweight serverless backends.</p>
<p>Let’s dive in.</p>
<hr />
<h2 id="heading-what-is-google-apps-script">💡 What is Google Apps Script?</h2>
<p>Google Apps Script is a JavaScript-based platform that lets you <strong>automate tasks across Google Workspace</strong>—including Sheets, Docs, Gmail, and more. It runs on Google’s servers, so you don’t have to worry about hosting, scaling, or maintenance. For small to medium-sized apps, it's a <strong>brilliant, cost-free solution</strong>.</p>
<p>Here’s what we’ll build:<br />✅ A feedback submission system<br />✅ A Google Sheets backend powered by Apps Script<br />✅ A frontend in Next.js that talks to the backend</p>
<hr />
<h2 id="heading-the-architecture">🌐 The Architecture</h2>
<p>Here’s the system flow:</p>
<pre><code class="lang-plaintext">[User Feedback Modal]
          |
          V
[Next.js API Route (/api/submit-feedback)]
          |
          V
[Google Apps Script Webhook]
          |
          V
[Google Spreadsheet (Icons Requests)]
</code></pre>
<hr />
<h2 id="heading-example">Example:</h2>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">🔍 <a target="_self" href="https://theicons.space/"><mark>TheIcons.space</mark></a> in Action</div>
</div>

<p>1️⃣ User clicks "Request Icon"<br />2️⃣ Feedback Modal opens (powered by Zustand)<br />3️⃣ User submits form<br />4️⃣ API call hits Google Apps Script<br />5️⃣ Google Sheets logs the request<br />6️⃣ You review icon requests in a simple, structured spreadsheet</p>
<hr />
<h2 id="heading-step-1-set-up-google-apps-script-with-google-sheets">📊 Step 1: Set Up Google Apps Script with Google Sheets</h2>
<p>1️⃣ <strong>Create a Google Sheet</strong></p>
<ul>
<li><p>Open <a target="_blank" href="https://sheets.google.com/">Google Sheets</a></p>
</li>
<li><p>Create a new sheet, name it something like <strong>"Icons Requests"</strong></p>
</li>
<li><p>In the sheet, add these column headers:</p>
<ul>
<li><p><strong>Timestamp</strong></p>
</li>
<li><p><strong>Icon Name</strong></p>
</li>
<li><p><strong>Description</strong></p>
</li>
</ul>
</li>
</ul>
<p>2️⃣ <strong>Create the Apps Script Backend</strong></p>
<ul>
<li><p>In your sheet, go to <code>Extensions &gt; Apps Script</code>.</p>
</li>
<li><p>Replace the default code with this:</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> SHEET_ID = <span class="hljs-string">'YOUR_SHEET_ID_HERE'</span>; <span class="hljs-comment">// Replace with your actual Sheet ID</span>
<span class="hljs-keyword">const</span> SHEET_NAME = <span class="hljs-string">'YOUR_SHEET_NAME'</span>; <span class="hljs-comment">// Replace with your actual sheet name (Bottom-left corner)</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doPost</span>(<span class="hljs-params">e</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(SHEET_NAME);
    <span class="hljs-keyword">const</span> data = <span class="hljs-built_in">JSON</span>.parse(e.postData.contents);

    sheet.appendRow([<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(), data.iconName, data.description || <span class="hljs-string">''</span>]);

    <span class="hljs-keyword">return</span> ContentService.createTextOutput(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">result</span>: <span class="hljs-string">'success'</span> }))
      .setMimeType(ContentService.MimeType.JSON);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> ContentService.createTextOutput(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">result</span>: <span class="hljs-string">'error'</span>, <span class="hljs-attr">error</span>: error.message }))
      .setMimeType(ContentService.MimeType.JSON);
  }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doGet</span>(<span class="hljs-params">e</span>) </span>{
  <span class="hljs-keyword">return</span> ContentService.createTextOutput(<span class="hljs-string">'Hello from Google Apps Script!'</span>);
}
</code></pre>
<ul>
<li><strong>Deploy the script</strong>:<br />  Go to <code>Deploy &gt; New deployment</code><br />  Choose <code>Web app</code>, give it a name, set access to <strong>Anyone</strong>, and deploy.<br />  Copy the URL—you’ll need it for the frontend!</li>
</ul>
<hr />
<h2 id="heading-step-2-add-webhook-url-in-env">🌍 Step 2: Add Webhook URL in <code>.env</code></h2>
<p>Add the webhook URL in your Next.js project:</p>
<pre><code class="lang-plaintext">GOOGLE_SHEET_WEBHOOK_URL=https://script.google.com/macros/s/your-script-id/exec
</code></pre>
<p>Never hardcode this in your code. Always use environment variables for security.</p>
<hr />
<h2 id="heading-step-3-connect-your-nextjs-app-to-google-sheets">🧩 Step 3: Connect Your Next.js App to Google Sheets</h2>
<p>Here’s a minimal <strong>FeedbackModal</strong> component that connects to your Apps Script backend:</p>
<pre><code class="lang-typescript"><span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Dialog, DialogContent, DialogTitle, DialogDescription, DialogClose } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ui/dialog"</span>;
<span class="hljs-keyword">import</span> { useFeedbackStore } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/lib/useFeedbackStore"</span>;
<span class="hljs-keyword">import</span> { Button } <span class="hljs-keyword">from</span> <span class="hljs-string">"./ui/button"</span>;
<span class="hljs-keyword">import</span> { toast } <span class="hljs-keyword">from</span> <span class="hljs-string">"sonner"</span>;

<span class="hljs-keyword">type</span> FeedbackModalProps = { requestedIcon?: <span class="hljs-built_in">string</span> };

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FeedbackModal</span>(<span class="hljs-params">{ requestedIcon }: FeedbackModalProps</span>) </span>{
  <span class="hljs-keyword">const</span> { isOpen, close } = useFeedbackStore();
  <span class="hljs-keyword">const</span> [iconName, setIconName] = useState(requestedIcon || <span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [description, setDescription] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-string">""</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> { setIconName(requestedIcon || <span class="hljs-string">""</span>); }, [requestedIcon]);

   <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    setLoading(<span class="hljs-literal">true</span>);

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"/api/submit-feedback"</span>, {
        method: <span class="hljs-string">"POST"</span>,
        headers: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> },
        body: <span class="hljs-built_in">JSON</span>.stringify({ iconName, description }),
      });

      <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json();
      <span class="hljs-keyword">if</span> (result.result === <span class="hljs-string">"success"</span>) {
        toast.success(<span class="hljs-string">"Feedback submitted!"</span>);
        setIconName(<span class="hljs-string">""</span>); setDescription(<span class="hljs-string">""</span>); close();
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(result.error || <span class="hljs-string">"Submission failed."</span>);
      }
    } <span class="hljs-keyword">catch</span> (error: <span class="hljs-built_in">any</span>) {
      toast.error(error.message);
    } <span class="hljs-keyword">finally</span> {
      setLoading(<span class="hljs-literal">false</span>);
    }
  };


  <span class="hljs-keyword">return</span> (
    &lt;Dialog open={isOpen} onOpenChange={close}&gt;
      &lt;DialogContent className=<span class="hljs-string">"max-w-md"</span>&gt;
        &lt;DialogTitle&gt;Request an Icon&lt;/DialogTitle&gt;
        &lt;DialogDescription&gt;Please provide details about the icon you are looking <span class="hljs-keyword">for</span>.&lt;/DialogDescription&gt;
        &lt;form onSubmit={handleSubmit} className=<span class="hljs-string">"space-y-4"</span>&gt;
          &lt;div&gt;
            &lt;label htmlFor=<span class="hljs-string">"iconName"</span>&gt;Icon Name &lt;span className=<span class="hljs-string">"text-red-600"</span>&gt;*&lt;<span class="hljs-regexp">/span&gt;&lt;/</span>label&gt;
            &lt;input id=<span class="hljs-string">"iconName"</span> value={iconName} onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setIconName(e.target.value)} placeholder=<span class="hljs-string">"e.g., Next.js"</span> className=<span class="hljs-string">"input"</span> required /&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;label htmlFor=<span class="hljs-string">"description"</span>&gt;Description&lt;/label&gt;
            &lt;textarea id=<span class="hljs-string">"description"</span> value={description} onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setDescription(e.target.value)} placeholder=<span class="hljs-string">"Any other details or use cases"</span> className=<span class="hljs-string">"textarea"</span> rows={<span class="hljs-number">3</span>} /&gt;
          &lt;/div&gt;
          {error &amp;&amp; &lt;p className=<span class="hljs-string">"text-red-600 text-sm"</span>&gt;{error}&lt;/p&gt;}
          &lt;div className=<span class="hljs-string">"flex justify-end space-x-3 pt-4"</span>&gt;
            &lt;DialogClose asChild&gt;&lt;Button <span class="hljs-keyword">type</span>=<span class="hljs-string">"button"</span> variant=<span class="hljs-string">"destructive"</span>&gt;Cancel&lt;<span class="hljs-regexp">/Button&gt;&lt;/</span>DialogClose&gt;
            &lt;Button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span> disabled={loading}&gt;{loading ? <span class="hljs-string">"Submitting..."</span> : <span class="hljs-string">"Submit"</span>}&lt;/Button&gt;
          &lt;/div&gt;
        &lt;/form&gt;
      &lt;/DialogContent&gt;
    &lt;/Dialog&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-step-4-connect-frontend-to-backend">🔗 Step 4: Connect Frontend to Backend</h2>
<p>Here’s how the <strong>Next.js API route</strong> (<code>/api/submit-feedback</code>) sends feedback to your Google Apps Script:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// pages/api/submit-feedback.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">if</span> (req.method !== <span class="hljs-string">'POST'</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">405</span>).end();

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(process.env.GOOGLE_SHEET_WEBHOOK_URL!, {
      method: <span class="hljs-string">'POST'</span>,
      headers: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
      body: <span class="hljs-built_in">JSON</span>.stringify(req.body),
    });

    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json();
    res.status(<span class="hljs-number">200</span>).json(result);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">500</span>).json({ result: <span class="hljs-string">'error'</span>, error: error.message });
  }
}
</code></pre>
<hr />
<h2 id="heading-step-5-zustand-store-for-modal-state">🗃️Step 5: Zustand Store for Modal State</h2>
<p>Simple state management for the feedback modal using Zustand:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { create } <span class="hljs-keyword">from</span> <span class="hljs-string">'zustand'</span>;

interface FeedbackState {
  <span class="hljs-attr">isOpen</span>: boolean;
  open: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span>;
  close: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useFeedbackStore = create&lt;FeedbackState&gt;(<span class="hljs-function">(<span class="hljs-params">set</span>) =&gt;</span> ({
  <span class="hljs-attr">isOpen</span>: <span class="hljs-literal">false</span>,
  <span class="hljs-attr">open</span>: <span class="hljs-function">() =&gt;</span> set({ <span class="hljs-attr">isOpen</span>: <span class="hljs-literal">true</span> }),
  <span class="hljs-attr">close</span>: <span class="hljs-function">() =&gt;</span> set({ <span class="hljs-attr">isOpen</span>: <span class="hljs-literal">false</span> }),
}));
</code></pre>
<hr />
<h2 id="heading-conclusion">🎯 Conclusion</h2>
<p>This system lets you collect user feedback directly into your Google Sheets, using a combination of:</p>
<p>✅ Google Apps Script for webhook handling<br />✅ Next.js API routes for frontend/backend communication<br />✅ Zustand for state management in React<br />✅ Environment variables for configuration</p>
<hr />
<h2 id="heading-why-use-google-apps-script">🛡️ Why Use Google Apps Script?</h2>
<p>✅ <strong>No Backend Hassle</strong>: No servers, no scaling headaches, no costs (up to quota).<br />✅ <strong>Integrates with Google Sheets</strong>: Your data is viewable, filterable, and exportable in Sheets.<br />✅ <strong>Rapid Prototyping</strong>: Build MVPs or internal tools <strong>fast</strong>.<br />✅ <strong>Secure</strong>: Authenticated via Google, no external DB leaks.</p>
<hr />
<h2 id="heading-the-big-picture">🚀 The Big Picture</h2>
<p>By combining <strong>Google Apps Script</strong> + <strong>Google Sheets</strong> + <strong>Next.js frontend</strong>, you create a lightweight but powerful system:</p>
<ul>
<li><p>Google Apps Script acts as your <strong>backend</strong>.</p>
</li>
<li><p>Google Sheets acts as your <strong>database</strong>.</p>
</li>
<li><p>Next.js provides a sleek <strong>frontend</strong>.</p>
</li>
</ul>
<p>This is the kind of <strong>lean architecture</strong> that helps you <strong>ship fast and stay agile</strong>—especially in early-stage projects or when testing ideas.</p>
]]></content:encoded></item><item><title><![CDATA[Building a Real-Time Chat App with Next.js and Socket.io (App Router)]]></title><description><![CDATA[Real-time applications, such as chat apps, require instant data exchange between clients and servers. In this guide, we'll walk through integrating Socket.io with Next.js (App Router) to build a real-time chat application.

🚀 Why Use Socket.io with ...]]></description><link>https://blogs.ishav.space/building-a-real-time-chat-app-with-nextjs-and-socketio-app-router</link><guid isPermaLink="true">https://blogs.ishav.space/building-a-real-time-chat-app-with-nextjs-and-socketio-app-router</guid><category><![CDATA[Next.js]]></category><category><![CDATA[SocketIO]]></category><category><![CDATA[chatapp]]></category><category><![CDATA[websockets]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sun, 02 Feb 2025 19:34:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738524447091/4550c4d6-a762-4e43-8c83-d0690b54c09a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Real-time applications, such as chat apps, require instant data exchange between clients and servers. In this guide, we'll walk through integrating <a target="_blank" href="https://socket.io/docs/v4/tutorial/introduction">Socket.io</a> with <a target="_blank" href="https://nextjs.org/docs/app/getting-started/installation"><strong>Next.js (App Router)</strong></a> to build a real-time chat application.</p>
<hr />
<h2 id="heading-why-use-socketio-with-nextjs">🚀 Why Use Socket.io with Next.js?</h2>
<p><strong>Socket.io</strong> is a powerful WebSocket library that enables bi-directional communication between the client and server. Next.js <strong>App Router (</strong><code>app/</code><strong>)</strong> does not support API routes, so we need a separate WebSocket server.</p>
<h3 id="heading-key-benefits"><strong>Key Benefits:</strong></h3>
<ul>
<li><p><strong>Low Latency:</strong> Instant message delivery between users.</p>
</li>
<li><p><strong>Separate WebSocket Server:</strong> Enhances scalability and flexibility.</p>
</li>
<li><p><strong>Works with App Router:</strong> Since API routes are not available in <code>app/</code>, using a dedicated WebSocket server is ideal.</p>
</li>
</ul>
<hr />
<h2 id="heading-setting-up-the-project">🛠️ Setting Up the Project</h2>
<h3 id="heading-step-1-create-a-nextjs-app"><strong>Step 1: Create a Next.js App</strong></h3>
<p>Run the following command to set up a Next.js project:</p>
<pre><code class="lang-typescript">npx create-next-app<span class="hljs-meta">@latest</span> nextjs-chat-app --typescript
cd nextjs-chat-app
</code></pre>
<h3 id="heading-step-2-install-dependencies"><strong>Step 2: Install Dependencies</strong></h3>
<p>You'll need <code>socket.io</code> for both the server and client:</p>
<pre><code class="lang-typescript">npm install socket.io socket.io-client
</code></pre>
<hr />
<h2 id="heading-backend-creating-a-websocket-server">🔧 Backend: Creating a WebSocket Server</h2>
<p>Since API routes are not available in App Router, we must run a separate WebSocket server.</p>
<h3 id="heading-step-3-create-serverts"><strong>Step 3: Create</strong> <code>server.ts</code></h3>
<p>📌 <strong>Create a</strong> <code>server.ts</code> <strong>file in the root directory:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { createServer } <span class="hljs-keyword">from</span> <span class="hljs-string">'http'</span>;
<span class="hljs-keyword">import</span> { Server <span class="hljs-keyword">as</span> SocketServer } <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io'</span>;

<span class="hljs-keyword">const</span> httpServer = createServer();
<span class="hljs-keyword">const</span> io = <span class="hljs-keyword">new</span> SocketServer(httpServer, {
  cors: { origin: <span class="hljs-string">'*'</span> },
});

io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'User connected:'</span>, socket.id);

  socket.on(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">msg</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Received message:'</span>, msg);
    io.emit(<span class="hljs-string">'message'</span>, msg);
  });

  socket.on(<span class="hljs-string">'disconnect'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'User disconnected:'</span>, socket.id);
  });
});

<span class="hljs-comment">// Start WebSocket server on port 3001</span>
httpServer.listen(<span class="hljs-number">3001</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'WebSocket server running on port 3001'</span>);
});
</code></pre>
<p>This server listens for WebSocket connections and handles real-time messaging.</p>
<hr />
<h2 id="heading-frontend-connecting-to-the-websocket-server">🖥️ Frontend: Connecting to the WebSocket Server</h2>
<h3 id="heading-step-4-create-a-chat-component"><strong>Step 4: Create a Chat Component</strong></h3>
<p>📌 <strong>Create</strong> <code>Chat.tsx</code> <strong>in</strong> <code>app/components/Chat.tsx</code><strong>:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-string">'use client'</span>;

<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { io, Socket } <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>;

<span class="hljs-keyword">let</span> socket: Socket;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Chat</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [message, setMessage] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [messages, setMessages] = useState&lt;<span class="hljs-built_in">string</span>[]&gt;([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    socket = io(<span class="hljs-string">'http://localhost:3001'</span>); <span class="hljs-comment">// Connect to WebSocket server</span>

    socket.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected:'</span>, socket.id);
    });

    socket.on(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">msg</span>) =&gt;</span> {
      setMessages(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> [...prev, msg]);
    });

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      socket.disconnect();
    };
  }, []);

  <span class="hljs-keyword">const</span> sendMessage = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (socket &amp;&amp; message.trim()) {
      socket.emit(<span class="hljs-string">'message'</span>, message);
      setMessage(<span class="hljs-string">''</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h2&gt;Real-Time Chat&lt;/h2&gt;
      &lt;div&gt;
        {messages.map(<span class="hljs-function">(<span class="hljs-params">msg, index</span>) =&gt;</span> (
          &lt;p key={index}&gt;{msg}&lt;/p&gt;
        ))}
      &lt;/div&gt;
      &lt;input
        <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
        value={message}
        onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setMessage(e.target.value)}
      /&gt;
      &lt;button onClick={sendMessage}&gt;Send&lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>This component connects to the WebSocket server, listens for messages, and allows users to send chat messages.</p>
<hr />
<h2 id="heading-step-5-add-chat-component-to-a-page">📄 Step 5: Add Chat Component to a Page</h2>
<p>📌 <strong>Modify</strong> <code>app/page.tsx</code> <strong>to include the chat:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> Chat <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Chat'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Next.js Real-Time Chat App&lt;/h1&gt;
      &lt;Chat /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-how-users-exchange-messages">🔄 How Users Exchange Messages</h2>
<p>Users will exchange messages in real-time through WebSockets. Here’s how it works:</p>
<ol>
<li><p><strong>Client connects to the WebSocket server</strong>:</p>
<ul>
<li>The <code>Chat.tsx</code> component initializes a connection to the WebSocket server running on <code>http://localhost:3001</code>.</li>
</ul>
</li>
<li><p><strong>Sending messages</strong>:</p>
<ul>
<li><p>When a user types a message and clicks "Send," the message is emitted using <code>socket.emit('message', message)</code>.</p>
</li>
<li><p>The server receives this message via the <code>socket.on('message', (msg) =&gt; { ... })</code> listener.</p>
</li>
</ul>
</li>
<li><p><strong>Broadcasting messages</strong>:</p>
<ul>
<li><p>The server listens for incoming messages and then emits the message to <strong>all connected clients</strong> using <code>io.emit('message', msg)</code>.</p>
</li>
<li><p>This ensures that every client (including the sender) receives the message in real time.</p>
</li>
</ul>
</li>
<li><p><strong>Receiving messages on the client</strong>:</p>
<ul>
<li><p>Every connected client listens for new messages with <code>socket.on('message', (msg) =&gt; { setMessages([...prevMessages, msg]) })</code>.</p>
</li>
<li><p>This updates the UI instantly with the received message.</p>
</li>
</ul>
</li>
</ol>
<p>By following this mechanism, multiple users can exchange messages in real time seamlessly.</p>
<hr />
<h2 id="heading-running-the-chat-app">🚀 Running the Chat App</h2>
<h3 id="heading-step-6-start-the-websocket-server"><strong>Step 6: Start the WebSocket Server</strong></h3>
<p>Before running your Next.js app, start the WebSocket server:</p>
<pre><code class="lang-typescript">node server.ts
</code></pre>
<h3 id="heading-step-7-start-your-nextjs-app"><strong>Step 7: Start Your Next.js App</strong></h3>
<p>Run Next.js separately:</p>
<pre><code class="lang-typescript">npm run dev
</code></pre>
<p>Visit <code>http://localhost:3000</code>, open multiple browser tabs, and chat in real-time!</p>
<hr />
<h2 id="heading-conclusion">📌 Conclusion</h2>
<p>By integrating <strong>Socket.io</strong> with <strong>Next.js (App Router)</strong>, you've built a fully functional real-time chat application. This guide covered:</p>
<ul>
<li><p><strong>Setting up a separate WebSocket server</strong> for Next.js App Router.</p>
</li>
<li><p><strong>Connecting the client</strong> to the WebSocket server using Socket.io.</p>
</li>
<li><p><strong>Implementing real-time messaging</strong> in a React component.</p>
</li>
</ul>
<h3 id="heading-next-steps"><strong>Next Steps:</strong></h3>
<p>✅ Add <strong>User Authentication</strong>: Secure messages for logged-in users. ✅ Store <strong>Chat History</strong>: Use Firebase, PostgreSQL, or MongoDB. ✅ Implement <strong>Group Chats &amp; Notifications</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738524572188/80e51318-f1b0-4a01-960e-7c157929640c.jpeg" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[How to Manage Global State in Next.js Using Redux Toolkit]]></title><description><![CDATA[Managing global state in a Next.js application can be tricky, but Redux Toolkit (RTK) makes it easier by reducing boilerplate and improving performance. In this guide, we’ll walk through integrating Redux Toolkit with Next.js to efficiently manage ap...]]></description><link>https://blogs.ishav.space/how-to-manage-global-state-in-nextjs-using-redux-toolkit</link><guid isPermaLink="true">https://blogs.ishav.space/how-to-manage-global-state-in-nextjs-using-redux-toolkit</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Redux]]></category><category><![CDATA[redux-toolkit]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sat, 01 Feb 2025 13:52:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738417834195/38175589-ddcb-4392-90cd-7649a96f6fbc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Managing global state in a Next.js application can be tricky, but Redux Toolkit (RTK) makes it easier by reducing boilerplate and improving performance. In this guide, we’ll walk through integrating Redux Toolkit with Next.js to efficiently manage application state.</p>
<hr />
<h2 id="heading-why-use-redux-toolkit-in-nextjs">Why Use Redux Toolkit in Next.js?</h2>
<p>Next.js is a powerful React framework with built-in features like SSR (Server-Side Rendering) and SSG (Static Site Generation). However, it doesn’t provide a built-in solution for global state management. That’s where Redux Toolkit comes in.</p>
<h3 id="heading-benefits-of-redux-toolkit">Benefits of Redux Toolkit:</h3>
<ul>
<li><p><strong>Less Boilerplate</strong>: Simplifies state management with built-in utilities.</p>
</li>
<li><p><strong>Efficient Performance</strong>: Uses Immer for immutable updates and Redux Thunk for async actions.</p>
</li>
<li><p><strong>Better Developer Experience</strong>: Includes built-in middleware and debugging tools.</p>
</li>
</ul>
<hr />
<h2 id="heading-setting-up-redux-toolkit-in-nextjs">Setting Up Redux Toolkit in Next.js</h2>
<h3 id="heading-step-1-install-dependencies">Step 1: Install Dependencies</h3>
<p>Run the following command in your Next.js project:</p>
<pre><code class="lang-typescript">npm install <span class="hljs-meta">@reduxjs</span>/toolkit react-redux
</code></pre>
<h3 id="heading-step-2-create-a-redux-store">Step 2: Create a Redux Store</h3>
<p>Inside your project, create a folder <code>store</code> and add a file called <code>store.ts</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// store/store.ts</span>
<span class="hljs-keyword">import</span> { configureStore } <span class="hljs-keyword">from</span> <span class="hljs-string">'@reduxjs/toolkit'</span>;
<span class="hljs-keyword">import</span> counterReducer <span class="hljs-keyword">from</span> <span class="hljs-string">'./slices/counterSlice'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> RootState = ReturnType&lt;<span class="hljs-keyword">typeof</span> store.getState&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> AppDispatch = <span class="hljs-keyword">typeof</span> store.dispatch;
</code></pre>
<h3 id="heading-step-3-create-a-slice">Step 3: Create a Slice</h3>
<p>Inside the <code>store</code> folder, create a <code>slices</code> directory and add <code>counterSlice.ts</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// store/slices/counterSlice.ts</span>
<span class="hljs-keyword">import</span> { createSlice } <span class="hljs-keyword">from</span> <span class="hljs-string">'@reduxjs/toolkit'</span>;

<span class="hljs-keyword">const</span> initialState = { value: <span class="hljs-number">0</span> };

<span class="hljs-keyword">const</span> counterSlice = createSlice({
  name: <span class="hljs-string">'counter'</span>,
  initialState,
  reducers: {
    increment: <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> {
      state.value += <span class="hljs-number">1</span>;
    },
    decrement: <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> {
      state.value -= <span class="hljs-number">1</span>;
    },
  },
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> { increment, decrement } = counterSlice.actions;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> counterSlice.reducer;
</code></pre>
<h3 id="heading-step-4-provide-the-store-to-nextjs">Step 4: Provide the Store to Next.js</h3>
<p>Next.js doesn’t have a built-in provider for Redux, so we wrap our app with the Redux Provider.</p>
<p>Modify <code>pages/_app.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// pages/_app.tsx</span>
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;
<span class="hljs-keyword">import</span> { store } <span class="hljs-keyword">from</span> <span class="hljs-string">'../store/store'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { AppProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/app'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }: AppProps</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;Provider store={store}&gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/Provider&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp;
</code></pre>
<h3 id="heading-step-5-use-redux-state-in-components">Step 5: Use Redux State in Components</h3>
<p>Now, let’s use Redux state in a component.</p>
<p>Create <code>components/Counter.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// components/Counter.tsx</span>
<span class="hljs-keyword">import</span> { useSelector, useDispatch } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;
<span class="hljs-keyword">import</span> { RootState } <span class="hljs-keyword">from</span> <span class="hljs-string">'../store/store'</span>;
<span class="hljs-keyword">import</span> { increment, decrement } <span class="hljs-keyword">from</span> <span class="hljs-string">'../store/slices/counterSlice'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> count = useSelector(<span class="hljs-function">(<span class="hljs-params">state: RootState</span>) =&gt;</span> state.counter.value);
  <span class="hljs-keyword">const</span> dispatch = useDispatch();

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Counter: {count}&lt;/h1&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> dispatch(increment())}&gt;+&lt;/button&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> dispatch(decrement())}&gt;-&lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<h3 id="heading-step-6-add-counter-to-a-page">Step 6: Add Counter to a Page</h3>
<p>Modify <code>pages/index.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// pages/index.tsx</span>
<span class="hljs-keyword">import</span> Counter <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/Counter'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Welcome to Redux Toolkit <span class="hljs-keyword">in</span> Next.js&lt;/h1&gt;
      &lt;Counter /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-using-redux-toolkit-with-the-nextjs-app-router">Using Redux Toolkit with the Next.js App Router</h2>
<p>If you’re using the <strong>App Router (app directory)</strong> in Next.js, the setup is slightly different. Instead of wrapping <code>_app.tsx</code>, you’ll use a provider in <code>layout.tsx</code>.</p>
<h3 id="heading-step-1-modify-storets-same-as-above">Step 1: Modify <code>store.ts</code> (Same as Above)</h3>
<h3 id="heading-step-2-provide-store-in-layouttsx">Step 2: Provide Store in <code>layout.tsx</code></h3>
<p>Modify <code>app/layout.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/layout.tsx</span>
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;
<span class="hljs-keyword">import</span> { store } <span class="hljs-keyword">from</span> <span class="hljs-string">'../store/store'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { ReactNode } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{ children }: { children: ReactNode }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;html lang=<span class="hljs-string">"en"</span>&gt;
      &lt;body&gt;
        &lt;Provider store={store}&gt;{children}&lt;/Provider&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  );
}
</code></pre>
<p>Use <code>‘use client’</code>, if <strong>This function is not supported in React Server Components. Please only use this export in a Client Component.</strong></p>
<h3 id="heading-step-3-use-redux-in-a-server-component">Step 3: Use Redux in a Server Component</h3>
<p>In the App Router, Redux is primarily used in Client Components. Mark components as <strong>'use client'</strong> at the top.</p>
<p>Modify <code>app/components/Counter.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/components/Counter.tsx</span>
<span class="hljs-string">'use client'</span>;
<span class="hljs-keyword">import</span> { useSelector, useDispatch } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;
<span class="hljs-keyword">import</span> { RootState } <span class="hljs-keyword">from</span> <span class="hljs-string">'../store/store'</span>;
<span class="hljs-keyword">import</span> { increment, decrement } <span class="hljs-keyword">from</span> <span class="hljs-string">'../store/slices/counterSlice'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> count = useSelector(<span class="hljs-function">(<span class="hljs-params">state: RootState</span>) =&gt;</span> state.counter.value);
  <span class="hljs-keyword">const</span> dispatch = useDispatch();

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Counter: {count}&lt;/h1&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> dispatch(increment())}&gt;+&lt;/button&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> dispatch(decrement())}&gt;-&lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<h3 id="heading-step-4-add-counter-to-a-page">Step 4: Add Counter to a Page</h3>
<p>Modify <code>app/page.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/page.tsx</span>
<span class="hljs-keyword">import</span> Counter <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Counter'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Welcome to Redux Toolkit <span class="hljs-keyword">in</span> Next.js (App Router)&lt;/h1&gt;
      &lt;Counter /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Redux Toolkit makes state management in Next.js simple and efficient. Whether you use the <strong>Pages Router or the App Router</strong>, the integration process is straightforward.</p>
<h3 id="heading-next-steps">Next Steps:</h3>
<ul>
<li><p>Explore <strong>Redux Persist</strong> to save state between page reloads.</p>
</li>
<li><p>Use <strong>RTK Query</strong> for fetching and caching data.</p>
</li>
<li><p>Implement <strong>middleware</strong> for advanced state management.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Integrating Next.js with Firebase]]></title><description><![CDATA[Firebase is a powerful backend-as-a-service platform that offers authentication, real-time databases, and hosting. Integrating Firebase with a Next.js application allows you to build scalable and serverless web applications with ease.

Why Use Fireba...]]></description><link>https://blogs.ishav.space/integrating-nextjs-with-firebase</link><guid isPermaLink="true">https://blogs.ishav.space/integrating-nextjs-with-firebase</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Firebase]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sat, 01 Feb 2025 12:46:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738183210862/32098d0d-ac00-46d8-87a2-60a67c3650f7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Firebase is a powerful backend-as-a-service platform that offers authentication, real-time databases, and hosting. Integrating Firebase with a Next.js application allows you to build scalable and serverless web applications with ease.</p>
<hr />
<h2 id="heading-why-use-firebase-with-nextjs">Why Use Firebase with Next.js?</h2>
<ul>
<li><p><strong>Authentication</strong>: Secure user authentication with Firebase Auth.</p>
</li>
<li><p><strong>Realtime Database &amp; Firestore</strong>: Sync data across clients instantly.</p>
</li>
<li><p><strong>Hosting</strong>: Deploy your Next.js app seamlessly using Firebase Hosting.</p>
</li>
<li><p><strong>Serverless Functions</strong>: Extend backend logic with Firebase Cloud Functions.</p>
</li>
</ul>
<hr />
<h2 id="heading-setting-up-firebase-in-nextjs">Setting Up Firebase in Next.js</h2>
<h3 id="heading-step-1-create-a-firebase-project">Step 1: Create a Firebase Project</h3>
<ol>
<li><p>Go to <a target="_blank" href="https://console.firebase.google.com">Firebase Console</a>.</p>
</li>
<li><p>Click <strong>Add Project</strong> and follow the setup steps.</p>
</li>
<li><p>Once created, go to <strong>Project Settings</strong> and get your Firebase credentials.</p>
</li>
</ol>
<h3 id="heading-step-2-install-firebase-sdk">Step 2: Install Firebase SDK</h3>
<p>Navigate to your Next.js project and install Firebase:</p>
<pre><code class="lang-bash">npm install firebase
</code></pre>
<h3 id="heading-step-3-configure-firebase">Step 3: Configure Firebase</h3>
<p>Create a <code>firebaseConfig.ts</code> file inside the <code>lib/</code> folder:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// lib/firebaseConfig.ts</span>
<span class="hljs-keyword">import</span> { initializeApp } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/app"</span>;
<span class="hljs-keyword">import</span> { getAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/auth"</span>;
<span class="hljs-keyword">import</span> { getFirestore } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/firestore"</span>;

<span class="hljs-keyword">const</span> firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};

<span class="hljs-keyword">const</span> app = initializeApp(firebaseConfig);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> auth = getAuth(app);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> db = getFirestore(app);
</code></pre>
<p>Add the environment variables in <code>.env.local</code>:</p>
<pre><code class="lang-plaintext">NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-auth-domain
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-storage-bucket
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-messaging-sender-id
NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id
</code></pre>
<hr />
<h2 id="heading-implementing-firebase-authentication">Implementing Firebase Authentication</h2>
<h3 id="heading-step-4-create-a-login-component">Step 4: Create a Login Component</h3>
<p>Create a simple authentication component using Firebase Auth:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// components/Login.tsx</span>
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { auth } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/firebaseConfig"</span>;
<span class="hljs-keyword">import</span> { signInWithEmailAndPassword, signOut } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/auth"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Login</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> handleLogin = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> signInWithEmailAndPassword(auth, email, password);
      alert(<span class="hljs-string">"Logged in successfully"</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error logging in:"</span>, error);
    }
  };

  <span class="hljs-keyword">const</span> handleLogout = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">await</span> signOut(auth);
    alert(<span class="hljs-string">"Logged out"</span>);
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"email"</span> placeholder=<span class="hljs-string">"Email"</span> onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setEmail(e.target.value)} /&gt;
      &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"password"</span> placeholder=<span class="hljs-string">"Password"</span> onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setPassword(e.target.value)} /&gt;
      &lt;button onClick={handleLogin}&gt;Login&lt;/button&gt;
      &lt;button onClick={handleLogout}&gt;Logout&lt;/button&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<h3 id="heading-step-5-protect-routes-using-middleware">Step 5: Protect Routes Using Middleware</h3>
<p>To restrict access to authenticated users, use Next.js middleware:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// middleware.ts</span>
<span class="hljs-keyword">import</span> { NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/server"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/server"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">req: NextRequest</span>) </span>{
  <span class="hljs-keyword">const</span> token = req.cookies.get(<span class="hljs-string">"auth-token"</span>);
  <span class="hljs-keyword">if</span> (!token) {
    <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">"/login"</span>, req.url));
  }
  <span class="hljs-keyword">return</span> NextResponse.next();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  matcher: <span class="hljs-string">"/dashboard/:path*"</span>,
};
</code></pre>
<hr />
<h2 id="heading-deploying-nextjs-with-firebase-hosting">Deploying Next.js with Firebase Hosting</h2>
<h3 id="heading-step-6-install-firebase-cli">Step 6: Install Firebase CLI</h3>
<p>If you haven’t installed Firebase CLI, run:</p>
<pre><code class="lang-bash">npm install -g firebase-tools
</code></pre>
<p>Login and initialize Firebase in your project:</p>
<pre><code class="lang-bash">firebase login
firebase init hosting
</code></pre>
<p>Choose:</p>
<ul>
<li><p><strong>Use an existing project</strong> (Select your Firebase project)</p>
</li>
<li><p><strong>Build directory</strong>: <code>.next</code></p>
</li>
<li><p><strong>Configure as a single-page app</strong>: No</p>
</li>
<li><p><strong>Set up automatic builds</strong>: No</p>
</li>
</ul>
<h3 id="heading-step-7-deploy">Step 7: Deploy</h3>
<p>Build your Next.js app and deploy it:</p>
<pre><code class="lang-bash">npm run build
firebase deploy
</code></pre>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Integrating Firebase with Next.js enables seamless authentication, database management, and hosting. With Firebase’s real-time capabilities and serverless infrastructure, you can build scalable web applications efficiently. Try Firebase to enhance your Next.js project with powerful backend functionalities!</p>
<p>For more details, check out the official documentation:</p>
<ul>
<li><p><a target="_blank" href="https://firebase.google.com/docs/guides?_gl=1*f8626b*_up*MQ..&amp;gclid=Cj0KCQiAwOe8BhCCARIsAGKeD57VcSc8l7fAJbJK6qj7O2Sdrfbv1B8mmTF1XXfWayN7kix1Zaxbh5saAqrIEALw_wcB&amp;gclsrc=aw.ds">Firebase Docs</a></p>
</li>
<li><p><a target="_blank" href="https://nextjs.org/docs/app/getting-started/installation">Next.js Docs</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Code Splitting and Bundling in Next.js]]></title><description><![CDATA[When building web applications, performance is everything. Users expect apps to load fast and feel responsive. That’s where code splitting and bundling come into play. These techniques ensure your app only loads the JavaScript it needs for a given pa...]]></description><link>https://blogs.ishav.space/code-splitting-and-bundling-in-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/code-splitting-and-bundling-in-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[codespliting]]></category><category><![CDATA[bundling]]></category><category><![CDATA[optimization]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sun, 26 Jan 2025 13:06:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737896681818/20ff59aa-56db-49aa-9aee-bebe42d04676.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When building web applications, performance is everything. Users expect apps to load fast and feel responsive. That’s where <strong>code splitting</strong> and <strong>bundling</strong> come into play. These techniques ensure your app only loads the JavaScript it needs for a given page or feature, reducing load times and improving overall performance.</p>
<p>In this blog, we’ll explore how <strong>Next.js</strong> handles code splitting and bundling out of the box and how you, as a developer, can take it to the next level.</p>
<hr />
<h2 id="heading-what-are-code-splitting-and-bundling">What Are Code Splitting and Bundling?</h2>
<h3 id="heading-code-splitting"><strong>Code Splitting</strong></h3>
<p>Code splitting breaks your app into smaller pieces (chunks) of JavaScript that are loaded on demand. Instead of sending one large file to the browser, you send only the necessary code for the specific page or feature being accessed.</p>
<h3 id="heading-bundling"><strong>Bundling</strong></h3>
<p>Bundling combines your app’s files into one or more JavaScript files. This process groups related files and dependencies, ensuring the app runs efficiently in the browser.</p>
<hr />
<h2 id="heading-how-nextjs-handles-code-splitting-and-bundling">How Next.js Handles Code Splitting and Bundling</h2>
<p>One of the great things about <strong>Next.js</strong> is that it automatically optimizes your app with <strong>built-in code splitting and bundling</strong>. Let’s break it down:</p>
<h3 id="heading-1-per-page-bundles">1. <strong>Per-Page Bundles</strong></h3>
<p>Next.js creates separate bundles for each page in your app. When a user visits a page, only the JavaScript required for that page is loaded. For example:</p>
<ul>
<li><p>Visiting <code>/about</code> only loads the code for the <code>pages/about.js</code> file and its dependencies.</p>
</li>
<li><p>The rest of the app’s code stays untouched until the user navigates to another page.</p>
</li>
</ul>
<p>This means smaller bundles and faster initial loads.</p>
<hr />
<h3 id="heading-2-shared-bundles">2. <strong>Shared Bundles</strong></h3>
<p>If multiple pages in your app use the same dependencies (e.g., React or a UI library), Next.js automatically extracts these into <strong>shared bundles</strong>. Shared bundles are cached by the browser, so users don’t need to download them multiple times.</p>
<hr />
<h3 id="heading-3-dynamic-imports">3. <strong>Dynamic Imports</strong></h3>
<p>Next.js supports <strong>dynamic imports</strong> for code splitting at the component level. This means you can load components only when they’re needed, not as part of the initial bundle.</p>
<p>Here’s an example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>;

<span class="hljs-keyword">const</span> DynamicComponent = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../components/HeavyComponent'</span>));

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomePage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Welcome to My App&lt;/h1&gt;
      &lt;DynamicComponent /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>In this case, <code>HeavyComponent</code> is only loaded when it’s rendered, reducing the initial load size.</p>
<hr />
<h2 id="heading-improving-code-splitting-and-bundling-in-nextjs">Improving Code Splitting and Bundling in Next.js</h2>
<p>While Next.js does a lot for you automatically, there are additional techniques you can use to further optimize your app.</p>
<h3 id="heading-1-analyze-your-bundle">1. <strong>Analyze Your Bundle</strong></h3>
<p>Next.js provides a built-in tool to analyze your app’s bundle size. You can use the <strong>Webpack Bundle Analyzer</strong> plugin to visualize your app’s bundles and identify opportunities to reduce their size.</p>
<h4 id="heading-how-to-enable-the-analyzer">How to Enable the Analyzer:</h4>
<p>Install the analyzer plugin:</p>
<pre><code class="lang-bash">npm install @next/bundle-analyzer
</code></pre>
<p>Update your <code>next.config.js</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> withBundleAnalyzer = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@next/bundle-analyzer'</span>)({
  enabled: process.env.ANALYZE === <span class="hljs-string">'true'</span>,
});

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = withBundleAnalyzer({});
</code></pre>
<p>Run the build with the analyzer:</p>
<pre><code class="lang-bash">ANALYZE=<span class="hljs-literal">true</span> npm run build
</code></pre>
<p>This generates a visual report of your app’s bundles, helping you spot large dependencies or unnecessary code.</p>
<hr />
<h3 id="heading-2-tree-shaking">2. <strong>Tree Shaking</strong></h3>
<p>Tree shaking is a process that removes unused code from your bundles. Next.js automatically performs tree shaking for libraries that support ES Modules. To make the most of this:</p>
<ul>
<li><p>Use modern libraries that support ES Modules.</p>
</li>
<li><p>Avoid importing everything from a library. Instead, import only what you need.</p>
</li>
</ul>
<h4 id="heading-example">Example:</h4>
<p>Instead of:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> _ <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash'</span>;
</code></pre>
<p>Use:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> debounce <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash/debounce'</span>;
</code></pre>
<hr />
<h3 id="heading-3-dynamic-imports-with-ssr">3. <strong>Dynamic Imports with SSR</strong></h3>
<p>Dynamic imports can be further optimized by disabling server-side rendering (SSR) for non-critical components. This can save server resources and improve client-side performance.</p>
<h4 id="heading-example-1">Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>;

<span class="hljs-keyword">const</span> NoSSRComponent = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../components/NoSSRComponent'</span>), { ssr: <span class="hljs-literal">false</span> });

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> &lt;NoSSRComponent /&gt;;
}
</code></pre>
<p>Here, <code>NoSSRComponent</code> is loaded only on the client, not during server rendering.</p>
<hr />
<h3 id="heading-4-code-splitting-css">4. <strong>Code Splitting CSS</strong></h3>
<p>If you’re using CSS in JS (e.g., Tailwind CSS or styled-components), Next.js automatically extracts critical CSS for each page. However, you can optimize further by:</p>
<ul>
<li><p>Removing unused CSS (using tools like <code>purgecss</code>).</p>
</li>
<li><p>Splitting CSS files into smaller chunks for large stylesheets.</p>
</li>
</ul>
<hr />
<h3 id="heading-5-optimize-images">5. <strong>Optimize Images</strong></h3>
<p>While not directly related to JavaScript bundling, optimizing images can significantly improve perceived performance. Next.js provides the <code>next/image</code> component, which automatically optimizes images for lazy loading and responsive sizes.</p>
<hr />
<h2 id="heading-real-world-example-optimized-nextjs-app">Real-World Example: Optimized Next.js App</h2>
<p>Let’s combine these techniques in a sample app:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>;
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">'next/image'</span>;

<span class="hljs-keyword">const</span> DynamicComponent = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../components/HeavyComponent'</span>), {
  loading: <span class="hljs-function">() =&gt;</span> &lt;p&gt;Loading...&lt;/p&gt;,
  ssr: <span class="hljs-literal">false</span>,
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomePage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Welcome to Optimized App&lt;/h1&gt;

      {<span class="hljs-comment">/* Lazy Loaded Image */</span>}
      &lt;Image
        src=<span class="hljs-string">"/images/optimized.jpg"</span>
        alt=<span class="hljs-string">"Optimized"</span>
        width={<span class="hljs-number">500</span>}
        height={<span class="hljs-number">300</span>}
      /&gt;

      {<span class="hljs-comment">/* Dynamically Imported Component */</span>}
      &lt;DynamicComponent /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<ol>
<li><p><strong>Next.js Automatically Optimizes</strong>:</p>
<ul>
<li><p>Per-page and shared bundles.</p>
</li>
<li><p>Tree shaking to remove unused code.</p>
</li>
</ul>
</li>
<li><p><strong>You Can Improve Further</strong>:</p>
<ul>
<li><p>Analyze your bundle using tools like <code>@next/bundle-analyzer</code>.</p>
</li>
<li><p>Use dynamic imports to split code at the component level.</p>
</li>
<li><p>Optimize dependencies and CSS.</p>
</li>
</ul>
</li>
<li><p><strong>Test Performance</strong>: Use tools like <strong>Lighthouse</strong> or <strong>WebPageTest</strong> to measure your app’s performance before and after optimization.</p>
</li>
</ol>
<hr />
<p>By leveraging Next.js’s built-in features and combining them with these techniques, you can create highly optimized web applications that load faster, perform better, and keep your users happy. 🚀</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737896736353/65d5a779-f7ce-4fa8-9dad-6fa8aac5539e.jpeg" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Implementing Lazy Loading in Next.js: Optimizing Images, Components, and Routes]]></title><description><![CDATA[As developers, we strive to create web applications that are fast, responsive, and optimized for the best user experience. One effective technique to achieve this is lazy loading, a method that loads content only when it’s needed, instead of loading ...]]></description><link>https://blogs.ishav.space/nextjs-lazy-loading</link><guid isPermaLink="true">https://blogs.ishav.space/nextjs-lazy-loading</guid><category><![CDATA[Next.js]]></category><category><![CDATA[lazy loading]]></category><category><![CDATA[optimization]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sat, 25 Jan 2025 16:35:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737822787971/855bbac4-16a5-4061-95fc-902d5cfa234e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As developers, we strive to create web applications that are fast, responsive, and optimized for the best user experience. One effective technique to achieve this is <strong>lazy loading</strong>, a method that loads content only when it’s needed, instead of loading everything upfront. This leads to faster initial load times, reduced bandwidth usage, and an overall smoother experience.</p>
<p>In this blog, we’ll dive into implementing lazy loading in a <strong>Next.js</strong> application, focusing on <strong>images</strong>, <strong>components</strong>, and <strong>routes</strong>.</p>
<hr />
<h2 id="heading-what-is-lazy-loading">What is Lazy Loading?</h2>
<p>Lazy loading is a design pattern where content is loaded only when it’s required, typically when it's about to be viewed or interacted with. This is particularly beneficial for assets like images, components, and even entire routes, which can be loaded asynchronously.</p>
<p>For example, imagine a page with a large image gallery. Without lazy loading, all images would load when the page is initially accessed, causing unnecessary delays. With lazy loading, images will only load when they are about to enter the viewport.</p>
<hr />
<h2 id="heading-benefits-of-lazy-loading">Benefits of Lazy Loading</h2>
<ol>
<li><p><strong>Improved Performance</strong>: By loading resources only when needed, you reduce the initial load time.</p>
</li>
<li><p><strong>Bandwidth Savings</strong>: Users only download the assets they actually view, saving data usage.</p>
</li>
<li><p><strong>Better SEO</strong>: Faster loading times can lead to better search engine rankings.</p>
</li>
<li><p><strong>Smoother User Experience</strong>: Reduces lag and enhances interaction with the website.</p>
</li>
</ol>
<hr />
<h2 id="heading-implementing-lazy-loading-in-nextjs">Implementing Lazy Loading in Next.js</h2>
<p>Now, let's walk through how to implement lazy loading for <strong>images</strong>, <strong>components</strong>, and <strong>routes</strong> in a Next.js project.</p>
<h3 id="heading-1-lazy-loading-images-in-nextjs">1. Lazy Loading Images in Next.js</h3>
<p>Next.js offers a built-in component called <code>next/image</code>, which supports <strong>lazy loading</strong> out of the box. By default, the images are only loaded when they’re about to appear in the viewport.</p>
<p>Here’s how you can use it:</p>
<h4 id="heading-example">Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">'next/image'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LazyLoadedImages</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Welcome to My Gallery&lt;/h1&gt;
      &lt;Image 
        src=<span class="hljs-string">"/images/photo.jpg"</span> 
        alt=<span class="hljs-string">"A beautiful scenery"</span> 
        width={<span class="hljs-number">500</span>} 
        height={<span class="hljs-number">300</span>} 
        priority={<span class="hljs-literal">false</span>}  <span class="hljs-comment">// Set priority to false for lazy loading</span>
      /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<ul>
<li><p><strong>priority</strong>: Setting <code>priority</code> to <code>true</code> will load the image immediately (useful for above-the-fold content), while setting it to <code>false</code> ensures lazy loading.</p>
</li>
<li><p><strong>Lazy loading</strong> is enabled by default, so you don’t have to do anything extra for most cases.</p>
</li>
</ul>
<h3 id="heading-2-lazy-loading-components">2. Lazy Loading Components</h3>
<p>In Next.js, you can easily load components lazily with <strong>dynamic imports</strong>. This allows you to split your JavaScript bundle, loading certain components only when they are required.</p>
<h4 id="heading-example-1">Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>;

<span class="hljs-keyword">const</span> LazyComponent = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../components/LazyComponent'</span>));

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomePage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Home Page&lt;/h1&gt;
      &lt;LazyComponent /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<h4 id="heading-how-it-works">How It Works:</h4>
<ul>
<li><p>The <code>dynamic</code> function allows the <code>LazyComponent</code> to be loaded only when it’s required.</p>
</li>
<li><p>You can also pass a loading fallback for the component while it’s loading.</p>
</li>
</ul>
<h4 id="heading-example-with-loading-fallback">Example with Loading Fallback:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> LazyComponent = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../components/LazyComponent'</span>), {
  loading: <span class="hljs-function">() =&gt;</span> &lt;p&gt;Loading...&lt;/p&gt;,
});
</code></pre>
<p>This shows a loading message until the component is ready to be displayed.</p>
<h3 id="heading-3-lazy-loading-routes-with-nextdynamic">3. Lazy Loading Routes with <code>next/dynamic</code></h3>
<p>Next.js also allows for lazy loading entire <strong>pages</strong> (or routes) using <code>next/dynamic</code>. This can be helpful for larger applications where some routes are not needed immediately.</p>
<h4 id="heading-example-2">Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>;

<span class="hljs-keyword">const</span> AboutPage = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../pages/about'</span>));

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomePage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Home Page&lt;/h1&gt;
      &lt;AboutPage /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>This method ensures that the About page is loaded only when needed.</p>
<hr />
<h2 id="heading-best-practices-for-lazy-loading">Best Practices for Lazy Loading</h2>
<p>While lazy loading is a powerful optimization tool, there are a few best practices to ensure it is used effectively:</p>
<h3 id="heading-1-avoid-overusing-lazy-loading-for-critical-content">1. <strong>Avoid Overusing Lazy Loading for Critical Content</strong></h3>
<p>While it’s tempting to lazy load everything, you should avoid lazy loading for content that’s crucial for the user’s immediate experience (e.g., navigation or above-the-fold content). These elements should be rendered as soon as possible to avoid delays.</p>
<h3 id="heading-2-use-priority-for-critical-assets">2. <strong>Use</strong> <code>priority</code> for Critical Assets</h3>
<p>For images and content that must appear immediately, you can use the <code>priority</code> attribute to load them first. This should be applied to images and components that are above the fold.</p>
<h3 id="heading-3-implement-fallbacks-for-lazy-loaded-components">3. <strong>Implement Fallbacks for Lazy Loaded Components</strong></h3>
<p>When lazy loading components, always provide a fallback UI (like a loading spinner) to enhance the user experience during the load time.</p>
<h3 id="heading-4-test-and-optimize">4. <strong>Test and Optimize</strong></h3>
<p>Always test the impact of lazy loading on your application’s performance. Use tools like <strong>Lighthouse</strong> to evaluate the effectiveness of your lazy loading implementation and ensure it’s improving the overall performance.</p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Lazy loading is an essential optimization technique to enhance the performance of your Next.js applications. Whether you’re optimizing images, components, or entire routes, lazy loading can significantly reduce your app's initial loading time and provide a smoother experience for your users.</p>
<p>By following the steps above, you can easily implement lazy loading in your Next.js projects, improving both performance and user experience. Happy coding! 🚀</p>
<hr />
<p><strong>Bonus Tip:</strong> Want to dive deeper into Next.js optimizations? Check out the official <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading"><mark>Next.js Lazy Loading documentation</mark></a> for more tips and advanced techniques.</p>
]]></content:encoded></item><item><title><![CDATA[SEO Best Practices in Next.js]]></title><description><![CDATA[Search Engine Optimization (SEO) is crucial for improving your website's visibility in search engines and driving organic traffic. Next.js, with its server-side rendering (SSR) capabilities, provides powerful tools to enhance SEO. In this guide, we’l...]]></description><link>https://blogs.ishav.space/seo-best-practices-in-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/seo-best-practices-in-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[SEO]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Wed, 22 Jan 2025 15:41:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737560434083/2f76ec5e-4c3a-45ce-919a-a3d11e1cb779.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Search Engine Optimization (SEO) is crucial for improving your website's visibility in search engines and driving organic traffic. Next.js, with its server-side rendering (SSR) capabilities, provides powerful tools to enhance SEO. In this guide, we’ll explore best practices for optimizing your Next.js app, focusing on <code>next/head</code> for meta tags, canonical URLs, and Open Graph data.</p>
<hr />
<h2 id="heading-why-is-seo-important">Why Is SEO Important?</h2>
<p>SEO ensures that your website ranks higher on search engine results pages (SERPs). This can lead to increased visibility, traffic, and conversions. By optimizing your Next.js app, you can:</p>
<ul>
<li><p>Improve page rankings.</p>
</li>
<li><p>Enhance user experience.</p>
</li>
<li><p>Drive organic traffic.</p>
</li>
</ul>
<hr />
<h2 id="heading-using-nexthead-for-seo">Using <code>next/head</code> for SEO</h2>
<p>The <code>next/head</code> component allows you to modify the <code>&lt;head&gt;</code> section of your HTML document dynamically. This is critical for adding meta tags, setting canonical URLs, and configuring Open Graph data.</p>
<h3 id="heading-step-1-add-nexthead-to-your-page-components">Step 1: Add <code>next/head</code> to Your Page Components</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">'next/head'</span>;

<span class="hljs-keyword">const</span> HomePage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      &lt;Head&gt;
        &lt;title&gt;Home | My Next.js App&lt;/title&gt;
        &lt;meta name=<span class="hljs-string">"description"</span> content=<span class="hljs-string">"Welcome to my Next.js app!"</span> /&gt;
        &lt;meta name=<span class="hljs-string">"keywords"</span> content=<span class="hljs-string">"Next.js, SEO, React"</span> /&gt;
        &lt;meta name=<span class="hljs-string">"author"</span> content=<span class="hljs-string">"Your Name"</span> /&gt;
        &lt;link rel=<span class="hljs-string">"canonical"</span> href=<span class="hljs-string">"https://example.com/"</span> /&gt;
        &lt;meta property=<span class="hljs-string">"og:title"</span> content=<span class="hljs-string">"Home | My Next.js App"</span> /&gt;
        &lt;meta property=<span class="hljs-string">"og:description"</span> content=<span class="hljs-string">"Welcome to my Next.js app!"</span> /&gt;
        &lt;meta property=<span class="hljs-string">"og:url"</span> content=<span class="hljs-string">"https://example.com/"</span> /&gt;
        &lt;meta property=<span class="hljs-string">"og:type"</span> content=<span class="hljs-string">"website"</span> /&gt;
      &lt;/Head&gt;
      &lt;h1&gt;Welcome to My Next.js App&lt;/h1&gt;
    &lt;/&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> HomePage;
</code></pre>
<h3 id="heading-key-elements">Key Elements:</h3>
<ul>
<li><p><strong>Title Tag</strong>: Sets the page title displayed in browser tabs and SERPs.</p>
</li>
<li><p><strong>Meta Description</strong>: Summarizes the page content for search engines.</p>
</li>
<li><p><strong>Keywords</strong>: Lists keywords relevant to the page (optional).</p>
</li>
<li><p><strong>Canonical URL</strong>: Prevents duplicate content issues by specifying the preferred URL.</p>
</li>
<li><p><strong>Open Graph (OG) Tags</strong>: Optimize social media sharing by providing metadata like title, description, and URL.</p>
</li>
</ul>
<hr />
<h2 id="heading-managing-canonical-urls">Managing Canonical URLs</h2>
<p>Canonical URLs help search engines understand the preferred version of a page, avoiding duplicate content issues. Use the <code>rel="canonical"</code> link tag in the <code>&lt;head&gt;</code> section.</p>
<h3 id="heading-example">Example:</h3>
<pre><code class="lang-typescript">&lt;link rel=<span class="hljs-string">"canonical"</span> href=<span class="hljs-string">"https://example.com/about"</span> /&gt;
</code></pre>
<p>Use dynamic values for pages with parameters:</p>
<pre><code class="lang-typescript">&lt;Head&gt;
  &lt;link rel=<span class="hljs-string">"canonical"</span> href={<span class="hljs-string">`https://example.com/<span class="hljs-subst">${slug}</span>`</span>} /&gt;
&lt;/Head&gt;
</code></pre>
<hr />
<h2 id="heading-open-graph-and-social-media-optimization">Open Graph and Social Media Optimization</h2>
<p>Open Graph metadata ensures that your content is displayed correctly when shared on social media platforms like Facebook, Twitter, and LinkedIn.</p>
<h3 id="heading-example-1">Example:</h3>
<pre><code class="lang-typescript">&lt;Head&gt;
  &lt;meta property=<span class="hljs-string">"og:title"</span> content=<span class="hljs-string">"About Us | My Next.js App"</span> /&gt;
  &lt;meta property=<span class="hljs-string">"og:description"</span> content=<span class="hljs-string">"Learn more about our team and mission."</span> /&gt;
  &lt;meta property=<span class="hljs-string">"og:image"</span> content=<span class="hljs-string">"https://example.com/og-image.jpg"</span> /&gt;
  &lt;meta property=<span class="hljs-string">"og:url"</span> content=<span class="hljs-string">"https://example.com/about"</span> /&gt;
  &lt;meta property=<span class="hljs-string">"og:type"</span> content=<span class="hljs-string">"website"</span> /&gt;
&lt;/Head&gt;
</code></pre>
<p>For Twitter, use <code>twitter:</code> meta tags:</p>
<pre><code class="lang-typescript">&lt;Head&gt;
  &lt;meta name=<span class="hljs-string">"twitter:card"</span> content=<span class="hljs-string">"summary_large_image"</span> /&gt;
  &lt;meta name=<span class="hljs-string">"twitter:title"</span> content=<span class="hljs-string">"About Us | My Next.js App"</span> /&gt;
  &lt;meta name=<span class="hljs-string">"twitter:description"</span> content=<span class="hljs-string">"Learn more about our team and mission."</span> /&gt;
  &lt;meta name=<span class="hljs-string">"twitter:image"</span> content=<span class="hljs-string">"https://example.com/twitter-image.jpg"</span> /&gt;
&lt;/Head&gt;
</code></pre>
<hr />
<h2 id="heading-dynamic-meta-tags-with-getserversideprops">Dynamic Meta Tags with getServerSideProps</h2>
<p>For pages with dynamic content, generate meta tags dynamically using <code>getServerSideProps</code> or <code>getStaticProps</code>.</p>
<h3 id="heading-example-with-getserversideprops">Example with <code>getServerSideProps</code>:</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params">context</span>) </span>{
  <span class="hljs-keyword">const</span> { slug } = context.params;
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://api.example.com/posts/<span class="hljs-subst">${slug}</span>`</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json());

  <span class="hljs-keyword">return</span> {
    props: {
      post: data,
    },
  };
}

<span class="hljs-keyword">const</span> PostPage = <span class="hljs-function">(<span class="hljs-params">{ post }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      &lt;Head&gt;
        &lt;title&gt;{post.title}&lt;/title&gt;
        &lt;meta name=<span class="hljs-string">"description"</span> content={post.excerpt} /&gt;
        &lt;link rel=<span class="hljs-string">"canonical"</span> href={<span class="hljs-string">`https://example.com/posts/<span class="hljs-subst">${post.slug}</span>`</span>} /&gt;
        &lt;meta property=<span class="hljs-string">"og:title"</span> content={post.title} /&gt;
        &lt;meta property=<span class="hljs-string">"og:description"</span> content={post.excerpt} /&gt;
      &lt;/Head&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;p&gt;{post.content}&lt;/p&gt;
    &lt;/&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PostPage;
</code></pre>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>By leveraging <code>next/head</code>, canonical URLs, and Open Graph metadata, you can significantly improve your Next.js app's SEO. These optimizations ensure better search engine visibility, improved user experience, and enhanced social media sharing. Start implementing these best practices to give your Next.js app a competitive edge.</p>
]]></content:encoded></item><item><title><![CDATA[Improving Performance with Lighthouse and Next.js]]></title><description><![CDATA[Performance is a critical factor for web applications, directly impacting user experience, SEO rankings, and conversion rates. Next.js, with its modern architecture, provides several built-in features to enhance performance. By combining these featur...]]></description><link>https://blogs.ishav.space/improving-performance-with-lighthouse-and-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/improving-performance-with-lighthouse-and-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[performance]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sat, 18 Jan 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737556876302/21c55209-1a88-4d2d-888e-7212ec7df4db.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Performance is a critical factor for web applications, directly impacting user experience, SEO rankings, and conversion rates. Next.js, with its modern architecture, provides several built-in features to enhance performance. By combining these features with tools like Google Lighthouse, you can analyze and optimize your app for speed and efficiency. This guide will show you how to use Lighthouse to identify performance bottlenecks and improve your Next.js app.</p>
<hr />
<h2 id="heading-what-is-lighthouse">What Is Lighthouse?</h2>
<p>Lighthouse is an open-source, automated tool by Google for auditing web applications. It provides scores and insights across several categories:</p>
<ul>
<li><p><strong>Performance</strong>: Measures loading speed and runtime performance.</p>
</li>
<li><p><strong>Accessibility</strong>: Ensures your app is usable by everyone.</p>
</li>
<li><p><strong>Best Practices</strong>: Highlights security and coding issues.</p>
</li>
<li><p><strong>SEO</strong>: Evaluates search engine optimization aspects.</p>
</li>
<li><p><strong>PWA</strong>: Checks Progressive Web App features.</p>
</li>
</ul>
<hr />
<h2 id="heading-step-1-running-a-lighthouse-audit">Step 1: Running a Lighthouse Audit</h2>
<p>You can run a Lighthouse audit directly from the Chrome DevTools:</p>
<ol>
<li><p><strong>Open Chrome DevTools</strong>:</p>
<ul>
<li><p>Right-click on your application and select <strong>Inspect</strong>.</p>
</li>
<li><p>Go to the <strong>Lighthouse</strong> tab.</p>
</li>
</ul>
</li>
<li><p><strong>Generate a Report</strong>:</p>
<ul>
<li><p>Select categories (e.g., Performance, SEO).</p>
</li>
<li><p>Choose the device type (mobile or desktop).</p>
</li>
<li><p>Click <strong>Generate report</strong>.</p>
</li>
</ul>
</li>
<li><p><strong>Analyze the Report</strong>:</p>
<ul>
<li>Lighthouse provides scores (0–100) and recommendations for improvement.</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-step-2-key-metrics-to-focus-on">Step 2: Key Metrics to Focus On</h2>
<p>Lighthouse evaluates performance based on these key metrics:</p>
<ol>
<li><p><strong>First Contentful Paint (FCP)</strong>: Time taken to render the first visible content.</p>
</li>
<li><p><strong>Largest Contentful Paint (LCP)</strong>: Time taken to render the largest visible content.</p>
</li>
<li><p><strong>Cumulative Layout Shift (CLS)</strong>: Measures visual stability.</p>
</li>
<li><p><strong>Time to Interactive (TTI)</strong>: Time until the app becomes fully interactive.</p>
</li>
<li><p><strong>Total Blocking Time (TBT)</strong>: Time during which the main thread is blocked.</p>
</li>
</ol>
<hr />
<h2 id="heading-step-3-optimizing-your-nextjs-app">Step 3: Optimizing Your Next.js App</h2>
<h3 id="heading-1-optimize-images">1. <strong>Optimize Images</strong></h3>
<p>Use the <code>next/image</code> component to serve optimized images.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">'next/image'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> &lt;Image src=<span class="hljs-string">"/example.jpg"</span> alt=<span class="hljs-string">"Example"</span> width={<span class="hljs-number">800</span>} height={<span class="hljs-number">600</span>} /&gt;;
}
</code></pre>
<p>Benefits:</p>
<ul>
<li><p>Automatic resizing for different devices.</p>
</li>
<li><p>Lazy loading by default.</p>
</li>
<li><p>WebP format support.</p>
</li>
</ul>
<h3 id="heading-2-enable-static-generation">2. <strong>Enable Static Generation</strong></h3>
<p>Leverage static site generation (SSG) for pages that don’t change frequently.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchData();
  <span class="hljs-keyword">return</span> { props: { data } };
}
</code></pre>
<h3 id="heading-3-use-dynamic-imports">3. <strong>Use Dynamic Imports</strong></h3>
<p>Load heavy components only when needed using dynamic imports.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>;

<span class="hljs-keyword">const</span> HeavyComponent = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./HeavyComponent'</span>));

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> &lt;HeavyComponent /&gt;;
}
</code></pre>
<h3 id="heading-4-optimize-fonts">4. <strong>Optimize Fonts</strong></h3>
<p>Use Next.js’s built-in font optimization feature.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Inter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/font/google'</span>;

<span class="hljs-keyword">const</span> inter = Inter({ subsets: [<span class="hljs-string">'latin'</span>] });

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> &lt;div className={inter.className}&gt;Hello, world!&lt;/div&gt;;
}
</code></pre>
<h3 id="heading-5-enable-compression">5. <strong>Enable Compression</strong></h3>
<p>Ensure responses are compressed by enabling gzip or Brotli compression.</p>
<h3 id="heading-6-analyze-and-bundle-splitting">6. <strong>Analyze and Bundle Splitting</strong></h3>
<p>Use the built-in <code>next build</code> analyzer to identify large bundles.</p>
<pre><code class="lang-typescript">npm run build --profile
</code></pre>
<p>Install the <code>@next/bundle-analyzer</code> package for detailed insights.</p>
<pre><code class="lang-typescript">npm install <span class="hljs-meta">@next</span>/bundle-analyzer
</code></pre>
<p>Add it to <code>next.config.js</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> withBundleAnalyzer = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@next/bundle-analyzer'</span>)({
  enabled: process.env.ANALYZE === <span class="hljs-string">'true'</span>,
});

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = withBundleAnalyzer({});
</code></pre>
<p>Run the build process with analysis:</p>
<pre><code class="lang-typescript">ANALYZE=<span class="hljs-literal">true</span> npm run build
</code></pre>
<hr />
<h2 id="heading-step-4-continuous-monitoring-and-testing">Step 4: Continuous Monitoring and Testing</h2>
<h3 id="heading-automate-lighthouse-audits">Automate Lighthouse Audits</h3>
<p>Use tools like <a target="_blank" href="https://github.com/GoogleChrome/lighthouse-ci">Lighthouse CI</a> to automate performance testing during deployments.</p>
<pre><code class="lang-typescript">npm install -g <span class="hljs-meta">@lhci</span>/cli
lhci autorun
</code></pre>
<h3 id="heading-use-vercel-analytics">Use Vercel Analytics</h3>
<p>Leverage Vercel’s built-in analytics to monitor performance metrics.</p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Optimizing performance is a continuous process. By combining the insights from Lighthouse with Next.js’s powerful features, you can create fast, efficient, and user-friendly applications. Regularly monitor your app’s performance and implement recommended best practices to stay ahead.</p>
<p>With tools like <code>next/image</code>, static generation, and bundle analysis, Next.js simplifies performance optimization, making it easier than ever to deliver an exceptional user experience.</p>
]]></content:encoded></item><item><title><![CDATA[Integrating GraphQL with Next.js]]></title><description><![CDATA[GraphQL has become a popular choice for managing API requests, thanks to its flexibility and efficiency in querying data. Combining GraphQL with Next.js allows developers to build powerful, scalable applications. In this guide, we’ll explore how to i...]]></description><link>https://blogs.ishav.space/integrating-graphql-with-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/integrating-graphql-with-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[GraphQL]]></category><category><![CDATA[Apollo GraphQL]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Fri, 17 Jan 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737479383893/1df1c590-0ab3-44d2-9cac-462771a4e3b1.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>GraphQL has become a popular choice for managing API requests, thanks to its flexibility and efficiency in querying data. Combining GraphQL with Next.js allows developers to build powerful, scalable applications. In this guide, we’ll explore how to integrate GraphQL with Next.js using Apollo Client for fetching data.</p>
<hr />
<h2 id="heading-why-use-graphql-with-nextjs">Why Use GraphQL with Next.js?</h2>
<ul>
<li><p><strong>Flexible Queries</strong>: Fetch only the data you need.</p>
</li>
<li><p><strong>Efficient Data Fetching</strong>: Reduce over-fetching and under-fetching of data.</p>
</li>
<li><p><strong>Strong Typing</strong>: GraphQL schemas provide clear definitions for APIs.</p>
</li>
<li><p><strong>Great for Modern Apps</strong>: Works seamlessly with Next.js’s data-fetching methods.</p>
</li>
</ul>
<hr />
<h2 id="heading-setting-up-apollo-client-in-nextjs">Setting Up Apollo Client in Next.js</h2>
<p>Apollo Client is a popular GraphQL client that simplifies data fetching and state management. </p>
<h3 id="heading-step-1-install-dependencies">Step 1: Install Dependencies</h3>
<p>Install Apollo Client and supporting libraries:</p>
<pre><code class="lang-typescript">npm install <span class="hljs-meta">@apollo</span>/client graphql
</code></pre>
<h3 id="heading-step-2-set-up-apollo-client">Step 2: Set Up Apollo Client</h3>
<p>Create an <code>apollo-client.ts</code> file in your project to configure the Apollo Client.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/apollo-client.ts</span>
<span class="hljs-keyword">import</span> { ApolloClient, InMemoryCache } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>;

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> ApolloClient({
  uri: <span class="hljs-string">'https://your-graphql-endpoint.com/graphql'</span>, <span class="hljs-comment">// Replace with your GraphQL endpoint</span>
  cache: <span class="hljs-keyword">new</span> InMemoryCache(),
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> client;
</code></pre>
<h3 id="heading-step-3-provide-apollo-client-to-your-app">Step 3: Provide Apollo Client to Your App</h3>
<p>Wrap your application with the ApolloProvider in the <code>layout.tsx</code> file or a custom <code>_app.tsx</code> (if using the pages directory).</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/layout.tsx</span>
<span class="hljs-keyword">import</span> { ApolloProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>;
<span class="hljs-keyword">import</span> client <span class="hljs-keyword">from</span> <span class="hljs-string">'../apollo-client'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{ children }: { children: React.ReactNode }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;html lang=<span class="hljs-string">"en"</span>&gt;
      &lt;body&gt;
        &lt;ApolloProvider client={client}&gt;{children}&lt;/ApolloProvider&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-fetching-data-with-apollo-client">Fetching Data with Apollo Client</h2>
<p>Apollo Client can fetch data on the client side or during server rendering in Next.js.</p>
<h3 id="heading-client-side-fetching">Client-Side Fetching</h3>
<p>Use Apollo’s <code>useQuery</code> hook to fetch data in a React component.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/products/page.tsx</span>
<span class="hljs-keyword">import</span> { gql, useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>;

<span class="hljs-keyword">const</span> GET_PRODUCTS = gql<span class="hljs-string">`
  query GetProducts {
    products {
      id
      name
      price
    }
  }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductsPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { loading, error, data } = useQuery(GET_PRODUCTS);

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> &lt;p&gt;Loading...&lt;/p&gt;;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> &lt;p&gt;<span class="hljs-built_in">Error</span>: {error.message}&lt;/p&gt;;

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Products&lt;/h1&gt;
      &lt;ul&gt;
        {data.products.map(<span class="hljs-function">(<span class="hljs-params">product: <span class="hljs-built_in">any</span></span>) =&gt;</span> (
          &lt;li key={product.id}&gt;{product.name} - ${product.price}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<h3 id="heading-server-side-rendering-ssr">Server-Side Rendering (SSR)</h3>
<p>Fetch data during server rendering using Apollo Client in Next.js’s <code>getServerSideProps</code> or <code>generateMetadata</code> (for app directory).</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/products/page.tsx</span>
<span class="hljs-keyword">import</span> { gql } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>;
<span class="hljs-keyword">import</span> client <span class="hljs-keyword">from</span> <span class="hljs-string">'../../apollo-client'</span>;

<span class="hljs-keyword">const</span> GET_PRODUCTS = gql<span class="hljs-string">`
  query GetProducts {
    products {
      id
      name
      price
    }
  }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductsPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> client.query({ query: GET_PRODUCTS });

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Products&lt;/h1&gt;
      &lt;ul&gt;
        {data.products.map(<span class="hljs-function">(<span class="hljs-params">product: <span class="hljs-built_in">any</span></span>) =&gt;</span> (
          &lt;li key={product.id}&gt;{product.name} - ${product.price}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-advanced-features">Advanced Features</h2>
<h3 id="heading-using-mutations">Using Mutations</h3>
<p>Mutations allow you to modify server-side data. Use the <code>useMutation</code> hook for client-side updates.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/products/AddProduct.tsx</span>
<span class="hljs-keyword">import</span> { gql, useMutation } <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>;

<span class="hljs-keyword">const</span> ADD_PRODUCT = gql<span class="hljs-string">`
  mutation AddProduct($name: String!, $price: Float!) {
    addProduct(name: $name, price: $price) {
      id
      name
    }
  }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AddProduct</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [addProduct] = useMutation(ADD_PRODUCT);

  <span class="hljs-keyword">const</span> handleAddProduct = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">await</span> addProduct({ variables: { name: <span class="hljs-string">'New Product'</span>, price: <span class="hljs-number">99.99</span> } });
    alert(<span class="hljs-string">'Product added!'</span>);
  };

  <span class="hljs-keyword">return</span> &lt;button onClick={handleAddProduct}&gt;Add Product&lt;/button&gt;;
}
</code></pre>
<h3 id="heading-optimistic-ui-updates">Optimistic UI Updates</h3>
<p>Apollo Client supports optimistic updates to provide a smoother user experience.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">await</span> addProduct({
  variables: { name: <span class="hljs-string">'New Product'</span>, price: <span class="hljs-number">99.99</span> },
  optimisticResponse: {
    addProduct: {
      id: <span class="hljs-string">'temp-id'</span>,
      name: <span class="hljs-string">'New Product'</span>,
      __typename: <span class="hljs-string">'Product'</span>,
    },
  },
});
</code></pre>
<hr />
<h2 id="heading-useful-links">Useful Links</h2>
<ul>
<li><p><a target="_blank" href="https://www.apollographql.com/blog/next-js-getting-started">Apollo Client Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://graphql.org/">GraphQL Official Website</a></p>
</li>
<li><p><a target="_blank" href="https://www.nextjs.org">Next.js Documentation</a></p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Integrating GraphQL with Next.js using Apollo Client enables developers to build modern, efficient, and flexible applications. Whether fetching data on the client or server, Apollo Client’s features simplify the process and enhance the user experience. Start exploring the power of GraphQL in your Next.js projects today!</p>
]]></content:encoded></item><item><title><![CDATA[Server Actions and React Server Components in Next.js]]></title><description><![CDATA[Next.js continues to evolve as a robust full-stack framework for building web applications. Two of its groundbreaking features—Server Actions and React Server Components (RSC)—enable developers to write performant, maintainable, and scalable applicat...]]></description><link>https://blogs.ishav.space/server-actions-and-react-server-components-in-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/server-actions-and-react-server-components-in-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[React]]></category><category><![CDATA[server]]></category><category><![CDATA[react server components]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Tue, 14 Jan 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737038704222/9c688050-de88-45ad-8670-edab49600ef0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Next.js continues to evolve as a robust full-stack framework for building web applications. Two of its groundbreaking features—<strong>Server Actions</strong> and <strong>React Server Components (RSC)</strong>—enable developers to write performant, maintainable, and scalable applications by optimizing server-side logic and client-side interactivity. This guide dives into these features, explaining their use cases and how to integrate them into your Next.js projects.</p>
<hr />
<h2 id="heading-react-server-components-rsc">React Server Components (RSC)</h2>
<p>React Server Components are a paradigm shift in how React applications are rendered. RSC allows components to run server-side while still being part of the React tree. This enables faster load times and reduces JavaScript payload on the client.</p>
<h3 id="heading-key-benefits-of-rsc">Key Benefits of RSC</h3>
<ol>
<li><p><strong>Improved Performance</strong>: Server-rendered components minimize client-side JavaScript.</p>
</li>
<li><p><strong>Reduced Bundle Size</strong>: By offloading logic to the server, you ship less code to the browser.</p>
</li>
<li><p><strong>Seamless Data Fetching</strong>: Fetch data directly within components without additional API calls.</p>
</li>
</ol>
<h3 id="heading-using-react-server-components-in-nextjs">Using React Server Components in Next.js</h3>
<p>In Next.js 13 and later, the <code>app</code> directory provides native support for React Server Components.</p>
<h4 id="heading-example-fetching-data-in-a-server-component">Example: Fetching Data in a Server Component</h4>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/products/page.tsx</span>

<span class="hljs-keyword">import</span> { fetchProducts } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/lib/api'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductsPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> fetchProducts();

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Products&lt;/h1&gt;
      &lt;ul&gt;
        {products.map(<span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> (
          &lt;li key={product.id}&gt;{product.name}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>In this example:</p>
<ul>
<li><p>The <code>fetchProducts</code> function runs server-side.</p>
</li>
<li><p>No JavaScript is sent to the client for this component, reducing the bundle size.</p>
</li>
</ul>
<h4 id="heading-passing-props-to-server-components">Passing Props to Server Components</h4>
<p>You can pass props to server components like regular React components. However, props should ideally be serializable or sourced from server-side logic.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Greeting</span>(<span class="hljs-params">{ name }: { name: <span class="hljs-built_in">string</span> }</span>) </span>{
  <span class="hljs-keyword">return</span> &lt;h1&gt;Hello, {name}!&lt;/h1&gt;;
}
</code></pre>
<hr />
<h2 id="heading-server-actions">Server Actions</h2>
<p>Server Actions simplify server-side logic by enabling functions to run on the server while maintaining the client’s interactivity. This feature is especially useful for scenarios like form submissions, mutations, or any interaction requiring server-side processing.</p>
<h3 id="heading-key-benefits-of-server-actions">Key Benefits of Server Actions</h3>
<ol>
<li><p><strong>Direct Server Communication</strong>: Invoke server-side logic without client-side APIs.</p>
</li>
<li><p><strong>Simplified State Management</strong>: Handle server updates without complex client-side state libraries.</p>
</li>
<li><p><strong>Security</strong>: Logic remains on the server, protecting sensitive operations.</p>
</li>
</ol>
<h3 id="heading-using-server-actions-in-nextjs">Using Server Actions in Next.js</h3>
<h4 id="heading-setting-up-server-actions">Setting Up Server Actions</h4>
<p>Server Actions work seamlessly with the <code>app</code> directory. Define server functions within components to execute server-side tasks.</p>
<h4 id="heading-example-form-submission-with-server-actions">Example: Form Submission with Server Actions</h4>
<pre><code class="lang-typescript"><span class="hljs-string">'use server'</span>;

<span class="hljs-keyword">import</span> { saveData } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/lib/db'</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleFormSubmit</span>(<span class="hljs-params">formData: FormData</span>) </span>{
  <span class="hljs-keyword">const</span> name = formData.get(<span class="hljs-string">'name'</span>);
  <span class="hljs-keyword">await</span> saveData({ name });
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ContactForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;form action={handleFormSubmit} method=<span class="hljs-string">"POST"</span>&gt;
      &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span> name=<span class="hljs-string">"name"</span> placeholder=<span class="hljs-string">"Your Name"</span> required /&gt;
      &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>&gt;Submit&lt;/button&gt;
    &lt;/form&gt;
  );
}
</code></pre>
<p>In this example:</p>
<ul>
<li><p>The <code>handleFormSubmit</code> function runs on the server.</p>
</li>
<li><p>No client-side JavaScript is needed for the form submission logic.</p>
</li>
</ul>
<hr />
<h2 id="heading-combining-server-actions-and-react-server-components">Combining Server Actions and React Server Components</h2>
<p>Server Actions and RSCs are complementary. Together, they enable clean separation of concerns, reducing client-side complexity while maintaining server-side efficiency.</p>
<h3 id="heading-example-dynamic-data-fetching-and-mutation">Example: Dynamic Data Fetching and Mutation</h3>
<pre><code class="lang-typescript"><span class="hljs-string">'use server'</span>;

<span class="hljs-keyword">import</span> { getItems, addItem } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/lib/api'</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleAddItem</span>(<span class="hljs-params">formData: FormData</span>) </span>{
  <span class="hljs-keyword">const</span> item = formData.get(<span class="hljs-string">'item'</span>);
  <span class="hljs-keyword">await</span> addItem(item);
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ItemList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> items = <span class="hljs-keyword">await</span> getItems();

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;ul&gt;
        {items.map(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> (
          &lt;li key={item.id}&gt;{item.name}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
      &lt;form action={handleAddItem} method=<span class="hljs-string">"POST"</span>&gt;
        &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span> name=<span class="hljs-string">"item"</span> placeholder=<span class="hljs-string">"Add Item"</span> required /&gt;
        &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>&gt;Add&lt;/button&gt;
      &lt;/form&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p><strong>Keep Logic Server-Side</strong>: Move expensive computations and sensitive logic to server components or server actions.</p>
</li>
<li><p><strong>Optimize Data Fetching</strong>: Combine server-side fetching with React’s suspense to streamline rendering.</p>
</li>
<li><p><strong>Minimize JavaScript on the Client</strong>: Use server components whenever possible to reduce the client’s JavaScript payload.</p>
</li>
</ol>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Server Actions and React Server Components transform how we build web applications with Next.js. By leveraging these features, developers can create faster, more secure, and scalable applications. With the ability to move logic server-side while maintaining a seamless user experience, Next.js continues to set the benchmark for modern web development.</p>
]]></content:encoded></item><item><title><![CDATA[Next.js API Rate Limiting with Middleware]]></title><description><![CDATA[As your application scales, managing API usage becomes crucial to maintain performance and security. Rate limiting is a key strategy to control the frequency of API requests, prevent abuse, and ensure fair usage among clients. In this guide, we’ll ex...]]></description><link>https://blogs.ishav.space/nextjs-api-rate-limiting-with-middleware</link><guid isPermaLink="true">https://blogs.ishav.space/nextjs-api-rate-limiting-with-middleware</guid><category><![CDATA[Next.js]]></category><category><![CDATA[ChaiCode]]></category><category><![CDATA[ratelimit]]></category><category><![CDATA[Middleware]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Tue, 14 Jan 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737461515432/46b472e3-516f-40d1-889a-8f9e460bc27f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As your application scales, managing API usage becomes crucial to maintain performance and security. Rate limiting is a key strategy to control the frequency of API requests, prevent abuse, and ensure fair usage among clients. In this guide, we’ll explore how to implement API rate limiting in a Next.js application using middleware.</p>
<hr />
<h2 id="heading-what-is-rate-limiting">What Is Rate Limiting?</h2>
<p>Rate limiting restricts the number of API requests a client can make within a specific time window. For example, you might allow a maximum of 100 requests per user per minute. If the limit is exceeded, the server responds with an error or throttles further requests.</p>
<h3 id="heading-benefits-of-rate-limiting">Benefits of Rate Limiting</h3>
<ul>
<li><p><strong>Improved Performance</strong>: Prevents server overload by controlling traffic.</p>
</li>
<li><p><strong>Security</strong>: Mitigates denial-of-service (DoS) attacks and other abuse.</p>
</li>
<li><p><strong>Fair Usage</strong>: Ensures all clients have equitable access to resources.</p>
</li>
</ul>
<hr />
<h2 id="heading-setting-up-middleware-for-rate-limiting-in-nextjs">Setting Up Middleware for Rate Limiting in Next.js</h2>
<p>Starting from Next.js 13, middleware provides an efficient way to process requests before they reach API routes or pages. We’ll leverage middleware to implement rate limiting.</p>
<h3 id="heading-step-1-install-dependencies">Step 1: Install Dependencies</h3>
<p>We’ll use the <code>upstash/ratelimit</code> package along with Upstash Redis for rate limiting. Install the required packages:</p>
<pre><code class="lang-typescript">npm install <span class="hljs-meta">@upstash</span>/redis <span class="hljs-meta">@upstash</span>/ratelimit
</code></pre>
<h3 id="heading-step-2-configure-upstash-redis">Step 2: Configure Upstash Redis</h3>
<ol>
<li><p>Create an account on <a target="_blank" href="https://upstash.com">Upstash</a>.</p>
</li>
<li><p>Set up a new Redis database and note the connection URL and token.</p>
</li>
</ol>
<h3 id="heading-step-3-implement-middleware">Step 3: Implement Middleware</h3>
<p>Create a <code>middleware.ts</code> file in the <code>src</code> directory to handle rate limiting.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/middleware.ts</span>
<span class="hljs-keyword">import</span> { NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;
<span class="hljs-keyword">import</span> { Redis } <span class="hljs-keyword">from</span> <span class="hljs-string">'@upstash/redis'</span>;
<span class="hljs-keyword">import</span> { Ratelimit } <span class="hljs-keyword">from</span> <span class="hljs-string">'@upstash/ratelimit'</span>;

<span class="hljs-comment">// Initialize Redis client</span>
<span class="hljs-keyword">const</span> redis = <span class="hljs-keyword">new</span> Redis({
  url: process.env.UPSTASH_REDIS_URL!,
  token: process.env.UPSTASH_REDIS_TOKEN!,
});

<span class="hljs-comment">// Initialize Ratelimit with Redis store</span>
<span class="hljs-keyword">const</span> ratelimit = <span class="hljs-keyword">new</span> Ratelimit({
  redis,
  limiter: Ratelimit.fixedWindow(<span class="hljs-number">100</span>, <span class="hljs-string">'1 m'</span>), <span class="hljs-comment">// 100 requests per minute</span>
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">req: Request</span>) </span>{
  <span class="hljs-keyword">const</span> ip = req.headers.get(<span class="hljs-string">'x-forwarded-for'</span>) || req.ip || <span class="hljs-string">'unknown'</span>;

  <span class="hljs-comment">// Check rate limit for the IP address</span>
  <span class="hljs-keyword">const</span> { success, reset } = <span class="hljs-keyword">await</span> ratelimit.limit(ip);

  <span class="hljs-keyword">if</span> (!success) {
    <span class="hljs-keyword">return</span> NextResponse.json(
      { error: <span class="hljs-string">'Too many requests. Please try again later.'</span> },
      { status: <span class="hljs-number">429</span>, headers: { <span class="hljs-string">'Retry-After'</span>: <span class="hljs-built_in">String</span>(reset) } }
    );
  }

  <span class="hljs-keyword">return</span> NextResponse.next();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  matcher: <span class="hljs-string">'/api/:path*'</span>, <span class="hljs-comment">// Apply middleware only to API routes</span>
};
</code></pre>
<h3 id="heading-how-it-works">How It Works:</h3>
<ol>
<li><p><strong>IP-Based Rate Limiting</strong>: The middleware extracts the client’s IP address and checks its request count using the <code>ratelimit</code> instance.</p>
</li>
<li><p><strong>Fixed Window</strong>: The rate limiter allows a maximum of 100 requests per IP per minute.</p>
</li>
<li><p><strong>Response on Exceeding Limit</strong>: If the client exceeds the limit, a <code>429 Too Many Requests</code> response is returned, with a <code>Retry-After</code> header indicating when they can retry.</p>
</li>
</ol>
<h3 id="heading-step-4-add-environment-variables">Step 4: Add Environment Variables</h3>
<p>Add the following environment variables to your <code>.env.local</code> file:</p>
<pre><code class="lang-typescript">UPSTASH_REDIS_URL=&lt;your-upstash-redis-url&gt;
UPSTASH_REDIS_TOKEN=&lt;your-upstash-redis-token&gt;
</code></pre>
<hr />
<h2 id="heading-testing-the-middleware">Testing the Middleware</h2>
<ol>
<li><p><strong>Start the Server</strong>: Run the development server:</p>
<pre><code class="lang-typescript"> npm run dev
</code></pre>
</li>
<li><p><strong>Send API Requests</strong>: Use a tool like <code>curl</code> or Postman to send requests to an API route (e.g., <code>/api/example</code>).</p>
</li>
<li><p><strong>Check Rate Limiting</strong>: After exceeding 100 requests per minute, you should receive a <code>429 Too Many Requests</code> error.</p>
</li>
</ol>
<pre><code class="lang-typescript">curl -X GET http:<span class="hljs-comment">//localhost:3000/api/example</span>
</code></pre>
<hr />
<h2 id="heading-enhancing-the-middleware">Enhancing the Middleware</h2>
<h3 id="heading-user-specific-rate-limiting">User-Specific Rate Limiting</h3>
<p>Instead of IP-based rate limiting, you can use a user’s authentication token or unique identifier.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> userId = req.headers.get(<span class="hljs-string">'authorization'</span>) || <span class="hljs-string">'unknown'</span>;
<span class="hljs-keyword">const</span> { success, reset } = <span class="hljs-keyword">await</span> ratelimit.limit(userId);
</code></pre>
<h3 id="heading-different-limits-for-different-routes">Different Limits for Different Routes</h3>
<p>You can customize rate limits for specific routes by modifying the middleware’s <code>matcher</code> configuration or checking the request URL.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">if</span> (req.nextUrl.pathname.startsWith(<span class="hljs-string">'/api/private'</span>)) {
  <span class="hljs-comment">// Stricter rate limit for private APIs</span>
  <span class="hljs-keyword">const</span> { success, reset } = <span class="hljs-keyword">await</span> ratelimit.limit(ip, { requests: <span class="hljs-number">50</span> });
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<hr />
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p><strong>Monitor Usage</strong>: Regularly review rate limit metrics to adjust limits as needed.</p>
</li>
<li><p><strong>Graceful Messaging</strong>: Provide informative error messages and retry headers.</p>
</li>
<li><p><strong>Test Thoroughly</strong>: Simulate high traffic to ensure the middleware handles edge cases.</p>
</li>
</ol>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Implementing API rate limiting in Next.js with middleware ensures secure and scalable API usage. By leveraging Upstash Redis and the <code>@upstash/ratelimit</code> package, you can effectively manage traffic and protect your application from abuse. Whether you’re building public APIs or internal tools, rate limiting is a vital strategy for maintaining performance and fairness.</p>
]]></content:encoded></item><item><title><![CDATA[Building a Multi-Tenant SaaS Platform with Next.js]]></title><description><![CDATA[Multi-tenant SaaS (Software as a Service) platforms allow multiple clients (tenants) to share a single application while maintaining separation of their data and configurations. In this guide, we will explore how to build a multi-tenant SaaS platform...]]></description><link>https://blogs.ishav.space/building-a-multi-tenant-saas-platform-with-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/building-a-multi-tenant-saas-platform-with-nextjs</guid><category><![CDATA[Next.js]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sat, 11 Jan 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736779524053/1bfc7a5b-ec57-43fb-afae-0e84b99e6608.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Multi-tenant SaaS (Software as a Service) platforms allow multiple clients (tenants) to share a single application while maintaining separation of their data and configurations. In this guide, we will explore how to build a multi-tenant SaaS platform using Next.js, leveraging its middleware and dynamic routing capabilities.</p>
<hr />
<h2 id="heading-key-concepts-in-multi-tenancy">Key Concepts in Multi-Tenancy</h2>
<h3 id="heading-1-tenant-identification">1. <strong>Tenant Identification</strong></h3>
<p>Each request must be associated with a specific tenant. This can be done through:</p>
<ul>
<li><p>Subdomains (e.g., <code>tenant1.example.com</code>)</p>
</li>
<li><p>Path-based routing (e.g., <code>example.com/tenant1</code>)</p>
</li>
<li><p>Custom headers (e.g., <code>X-Tenant-ID</code>)</p>
</li>
</ul>
<h3 id="heading-2-tenant-isolation">2. <strong>Tenant Isolation</strong></h3>
<p>Ensure data isolation between tenants. This involves:</p>
<ul>
<li><p>Separate database schemas or collections per tenant</p>
</li>
<li><p>Scoped configurations for themes, permissions, or features</p>
</li>
</ul>
<h3 id="heading-3-custom-branding">3. <strong>Custom Branding</strong></h3>
<p>Allow tenants to customize the application, such as uploading logos or changing colors, while sharing the same codebase.</p>
<hr />
<h2 id="heading-setting-up-dynamic-routing-in-nextjs">Setting Up Dynamic Routing in Next.js</h2>
<p>Dynamic routing in Next.js enables tenant-specific pages. Let’s implement a path-based routing structure.</p>
<h3 id="heading-folder-structure">Folder Structure</h3>
<pre><code class="lang-typescript">src
├── app
│   ├── [tenant]
│   │   ├── dashboard
│   │   │   └── page.tsx
│   │   ├── settings
│   │   │   └── page.tsx
│   ├── middleware.ts
</code></pre>
<p>In this structure:</p>
<ul>
<li><p><code>[tenant]</code> is a dynamic segment that matches tenant identifiers.</p>
</li>
<li><p>Pages like <code>/[tenant]/dashboard</code> and <code>/[tenant]/settings</code> serve tenant-specific content.</p>
</li>
</ul>
<h3 id="heading-dynamic-routes">Dynamic Routes</h3>
<p>Create tenant-specific pages using dynamic segments:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/navigation'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DashboardPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> { tenant } = router.query;

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Welcome, {tenant}&lt;/h1&gt;
      &lt;p&gt;This is the dashboard <span class="hljs-keyword">for</span> tenant: {tenant}&lt;/p&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-using-middleware-for-tenant-identification">Using Middleware for Tenant Identification</h2>
<p>Middleware in Next.js can intercept requests and perform tasks such as tenant identification and redirection.</p>
<h3 id="heading-middleware-example">Middleware Example</h3>
<p>Create a <code>middleware.ts</code> file in the <code>app</code> directory:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">req</span>) </span>{
  <span class="hljs-keyword">const</span> url = req.nextUrl;
  <span class="hljs-keyword">const</span> tenant = url.pathname.split(<span class="hljs-string">'/'</span>)[<span class="hljs-number">1</span>];

  <span class="hljs-keyword">if</span> (!tenant) {
    <span class="hljs-comment">// Redirect to a generic landing page if no tenant is specified</span>
    <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/landing'</span>, req.url));
  }

  <span class="hljs-comment">// Add tenant to the request headers for downstream processing</span>
  req.headers.set(<span class="hljs-string">'x-tenant-id'</span>, tenant);

  <span class="hljs-keyword">return</span> NextResponse.next();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  matcher: <span class="hljs-string">'/:path*'</span>,
};
</code></pre>
<p>This middleware:</p>
<ol>
<li><p>Extracts the tenant from the URL path.</p>
</li>
<li><p>Redirects users without a tenant to a landing page.</p>
</li>
<li><p>Adds the tenant identifier to the request headers for further use.</p>
</li>
</ol>
<hr />
<h2 id="heading-data-isolation-for-tenants">Data Isolation for Tenants</h2>
<h3 id="heading-database-design">Database Design</h3>
<ul>
<li><p><strong>Single Database with Tenant ID</strong>: Add a <code>tenantId</code> field to each record.</p>
</li>
<li><p><strong>Separate Databases or Schemas</strong>: Use a unique database or schema for each tenant.</p>
</li>
</ul>
<h3 id="heading-fetching-tenant-data">Fetching Tenant Data</h3>
<p>Modify API calls to include tenant-specific filters:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">const</span> tenantId = req.headers[<span class="hljs-string">'x-tenant-id'</span>];

  <span class="hljs-comment">// Fetch data scoped to the tenant</span>
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchDataForTenant(tenantId);

  res.status(<span class="hljs-number">200</span>).json(data);
}
</code></pre>
<hr />
<h2 id="heading-custom-branding-and-configurations">Custom Branding and Configurations</h2>
<p>Allow tenants to upload their own assets or set configurations.</p>
<h3 id="heading-example-tenant-themes">Example: Tenant Themes</h3>
<h4 id="heading-define-theme-configurations">Define Theme Configurations</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> tenantThemes = {
  tenant1: { primaryColor: <span class="hljs-string">'#ff0000'</span>, logo: <span class="hljs-string">'/logos/tenant1.png'</span> },
  tenant2: { primaryColor: <span class="hljs-string">'#0000ff'</span>, logo: <span class="hljs-string">'/logos/tenant2.png'</span> },
};
</code></pre>
<h4 id="heading-apply-themes-in-components">Apply Themes in Components</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/router'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Header</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> { tenant } = router.query;

  <span class="hljs-keyword">const</span> theme = tenantThemes[tenant] || tenantThemes[<span class="hljs-string">'default'</span>];

  <span class="hljs-keyword">return</span> (
    &lt;header style={{ backgroundColor: theme.primaryColor }}&gt;
      &lt;img src={theme.logo} alt={<span class="hljs-string">`<span class="hljs-subst">${tenant}</span> logo`</span>} /&gt;
    &lt;/header&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-benefits-of-using-nextjs-for-multi-tenancy">Benefits of Using Next.js for Multi-Tenancy</h2>
<ol>
<li><p><strong>Simplified Routing</strong>: Dynamic routing makes tenant-specific URLs easy to implement.</p>
</li>
<li><p><strong>Built-In Middleware</strong>: Next.js middleware simplifies tenant identification and request handling.</p>
</li>
<li><p><strong>Scalable Architecture</strong>: ISR and API routes support high traffic while maintaining performance.</p>
</li>
<li><p><strong>Customizable UI</strong>: Tenant-specific branding and themes enhance the user experience.</p>
</li>
</ol>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Building a multi-tenant SaaS platform with Next.js is efficient and scalable. By leveraging middleware and dynamic routing, you can create tenant-specific experiences while maintaining a shared codebase. With proper database design and configuration management, you can ensure data isolation and customization for each tenant, paving the way for a robust and flexible SaaS application.</p>
]]></content:encoded></item><item><title><![CDATA[Incremental Static Regeneration (ISR): A Deep Dive]]></title><description><![CDATA[Next.js offers powerful rendering methods, one of which is Incremental Static Regeneration (ISR). This technique combines the performance benefits of static generation with the flexibility of server-side updates. In this guide, we'll explore how ISR ...]]></description><link>https://blogs.ishav.space/incremental-static-regeneration-isr-a-deep-dive</link><guid isPermaLink="true">https://blogs.ishav.space/incremental-static-regeneration-isr-a-deep-dive</guid><category><![CDATA[Next.js]]></category><category><![CDATA[isr]]></category><category><![CDATA[Vercel]]></category><category><![CDATA[next js hybrid rendering]]></category><category><![CDATA[cache]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Fri, 10 Jan 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736698911876/b8e9c342-837e-4b9b-b7a9-259655e9f095.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Next.js offers powerful rendering methods, one of which is Incremental Static Regeneration (ISR). This technique combines the performance benefits of static generation with the flexibility of server-side updates. In this guide, we'll explore how ISR works, its impact on performance, scalability, and practical use cases.</p>
<hr />
<h2 id="heading-what-is-incremental-static-regeneration-isr">What is Incremental Static Regeneration (ISR)?</h2>
<p>Incremental Static Regeneration allows you to update static content on a per-page basis without rebuilding the entire site. This enables dynamic content updates while preserving the speed of static generation.</p>
<h3 id="heading-key-features-of-isr">Key Features of ISR:</h3>
<ul>
<li><p><strong>Selective Rebuilding</strong>: Only the pages with updated content are regenerated.</p>
</li>
<li><p><strong>Hybrid Rendering</strong>: Combines static and dynamic rendering strategies.</p>
</li>
<li><p><strong>Fast Performance</strong>: Users always get the static version while a background regeneration occurs for updated content.</p>
</li>
</ul>
<hr />
<h2 id="heading-how-isr-works">How ISR Works</h2>
<p>When a user visits a page:</p>
<ol>
<li><p><strong>Static Content Served</strong>: The statically generated version of the page is served from the cache.</p>
</li>
<li><p><strong>Background Regeneration</strong>: If the page is older than the defined revalidation period, Next.js regenerates it in the background.</p>
</li>
<li><p><strong>Cache Update</strong>: The newly regenerated page replaces the older version in the cache.</p>
</li>
<li><p><strong>Updated Content</strong>: Future users see the updated page.</p>
</li>
</ol>
<hr />
<h2 id="heading-implementing-isr-in-nextjs">Implementing ISR in Next.js</h2>
<p>ISR is configured using the <code>revalidate</code> property in <code>getStaticProps</code>. Here's an example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { GetStaticProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BlogPost</span>(<span class="hljs-params">{ post }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;article&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;p&gt;{post.content}&lt;/p&gt;
    &lt;/article&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getStaticProps: GetStaticProps = <span class="hljs-keyword">async</span> (context) =&gt; {
  <span class="hljs-keyword">const</span> { id } = context.params;

  <span class="hljs-comment">// Fetch the blog post data from an API or database</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://api.example.com/posts/<span class="hljs-subst">${id}</span>`</span>);
  <span class="hljs-keyword">const</span> post = <span class="hljs-keyword">await</span> res.json();

  <span class="hljs-keyword">return</span> {
    props: {
      post,
    },
    revalidate: <span class="hljs-number">60</span>, <span class="hljs-comment">// Revalidate every 60 seconds</span>
  };
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticPaths</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/posts'</span>);
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> res.json();

  <span class="hljs-keyword">const</span> paths = posts.map(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> ({
    params: { id: post.id.toString() },
  }));

  <span class="hljs-keyword">return</span> { paths, fallback: <span class="hljs-string">'blocking'</span> };
}
</code></pre>
<p>In this example:</p>
<ul>
<li><p>The page revalidates every 60 seconds.</p>
</li>
<li><p>If a user visits after the revalidation period, the content is updated in the background.</p>
</li>
</ul>
<hr />
<h2 id="heading-use-cases-for-isr">Use Cases for ISR</h2>
<h3 id="heading-1-e-commerce-websites">1. <strong>E-Commerce Websites</strong></h3>
<ul>
<li><p>Update product inventory or pricing dynamically.</p>
</li>
<li><p>Regenerate only the updated product pages.</p>
</li>
</ul>
<h3 id="heading-2-news-platforms">2. <strong>News Platforms</strong></h3>
<ul>
<li>Serve static versions of articles while allowing updates for breaking news or corrections.</li>
</ul>
<h3 id="heading-3-content-driven-sites">3. <strong>Content-Driven Sites</strong></h3>
<ul>
<li>Blogs or documentation sites where content changes periodically.</li>
</ul>
<hr />
<h2 id="heading-benefits-of-isr">Benefits of ISR</h2>
<h3 id="heading-1-improved-performance"><strong>1. Improved Performance</strong></h3>
<ul>
<li>Content is served statically, reducing server load and latency.</li>
</ul>
<h3 id="heading-2-scalability"><strong>2. Scalability</strong></h3>
<ul>
<li>Efficiently handle high traffic without regenerating the entire site.</li>
</ul>
<h3 id="heading-3-dynamic-updates"><strong>3. Dynamic Updates</strong></h3>
<ul>
<li>Keep content fresh without needing a full rebuild.</li>
</ul>
<h3 id="heading-4-seo-optimization"><strong>4. SEO Optimization</strong></h3>
<ul>
<li>Pages are served as fully rendered HTML, ensuring better crawlability.</li>
</ul>
<hr />
<h2 id="heading-debugging-and-monitoring-isr">Debugging and Monitoring ISR</h2>
<h3 id="heading-1-logs-and-metrics"><strong>1. Logs and Metrics</strong></h3>
<ul>
<li>Monitor ISR behavior using server logs to track regeneration events.</li>
</ul>
<h3 id="heading-2-on-demand-revalidation"><strong>2. On-Demand Revalidation</strong></h3>
<ul>
<li>Use the <code>res.revalidate</code> method in API routes to manually trigger regeneration:</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">await</span> res.revalidate(<span class="hljs-string">'/path-to-revalidate'</span>);
  res.json({ revalidated: <span class="hljs-literal">true</span> });
}
</code></pre>
<hr />
<h2 id="heading-limitations-and-considerations">Limitations and Considerations</h2>
<h3 id="heading-1-cache-invalidation-delay"><strong>1. Cache Invalidation Delay</strong></h3>
<ul>
<li>Users may see outdated content until the regeneration is complete.</li>
</ul>
<h3 id="heading-2-api-dependency"><strong>2. API Dependency</strong></h3>
<ul>
<li>Ensure your API can handle frequent requests for data fetching.</li>
</ul>
<h3 id="heading-3-revalidation-costs"><strong>3. Revalidation Costs</strong></h3>
<ul>
<li>Consider the cost of regenerating pages when scaling to a large number of users.</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Incremental Static Regeneration bridges the gap between static and dynamic rendering. It empowers developers to deliver high-performance applications with fresh content updates, making it a crucial feature for modern web development. With ISR, you can build scalable, performant, and user-friendly Next.js applications.</p>
]]></content:encoded></item><item><title><![CDATA[Implementing Authentication in Next.js with NextAuth.js]]></title><description><![CDATA[NextAuth.js is a popular authentication library for Next.js that simplifies the process of implementing user authentication. It provides a robust and customizable solution for handling different authentication methods, including credentials, OAuth pr...]]></description><link>https://blogs.ishav.space/implementing-authentication-in-nextjs-with-nextauthjs</link><guid isPermaLink="true">https://blogs.ishav.space/implementing-authentication-in-nextjs-with-nextauthjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[nextauth.js]]></category><category><![CDATA[authentication]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Wed, 08 Jan 2025 11:57:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736336688962/53884770-79f1-4277-b862-8f8972a7dce3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>NextAuth.js is a popular authentication library for Next.js that simplifies the process of implementing user authentication. It provides a robust and customizable solution for handling different authentication methods, including credentials, OAuth providers, and more. This guide walks you through setting up a basic authentication system in a Next.js application using NextAuth.js.</p>
<hr />
<h2 id="heading-step-1-install-nextauthjs">Step 1: Install NextAuth.js</h2>
<p>First, install NextAuth.js and the necessary dependencies:</p>
<pre><code class="lang-bash">npm install next-auth @next-auth/prisma-adapter
</code></pre>
<p>If you plan to use a database, make sure you have an ORM like Prisma or an appropriate adapter installed.</p>
<hr />
<h2 id="heading-step-2-create-an-api-route-for-authentication">Step 2: Create an API Route for Authentication</h2>
<p>NextAuth.js requires an API route to handle authentication requests. Create a new file <code>src/pages/api/auth/[...nextauth].ts</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> NextAuth <span class="hljs-keyword">from</span> <span class="hljs-string">'next-auth'</span>;
<span class="hljs-keyword">import</span> Providers <span class="hljs-keyword">from</span> <span class="hljs-string">'next-auth/providers'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> NextAuth({
  providers: [
    Providers.GitHub({
      clientId: process.env.GITHUB_CLIENT_ID,
      clientSecret: process.env.GITHUB_CLIENT_SECRET,
    }),
    <span class="hljs-comment">// Add more providers as needed</span>
  ],
  callbacks: {
    <span class="hljs-keyword">async</span> session({ session, user }) {
      session.user.id = user.id;
      <span class="hljs-keyword">return</span> session;
    },
  },
  secret: process.env.NEXTAUTH_SECRET,
});
</code></pre>
<p>This configuration uses GitHub as an OAuth provider. Replace <code>GITHUB_CLIENT_ID</code> and <code>GITHUB_CLIENT_SECRET</code> with your GitHub app credentials. You can add other providers as needed.</p>
<hr />
<h2 id="heading-step-3-configure-environment-variables">Step 3: Configure Environment Variables</h2>
<p>Add the required environment variables in a <code>.env.local</code> file at the root of your project:</p>
<pre><code class="lang-typescript">GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
NEXTAUTH_URL=http:<span class="hljs-comment">//localhost:3000</span>
NEXTAUTH_SECRET=your_secret_key
</code></pre>
<p>Replace <code>your_github_client_id</code>, <code>your_github_client_secret</code>, and <code>your_secret_key</code> with appropriate values.</p>
<hr />
<h2 id="heading-step-4-protect-pages-using-middleware">Step 4: Protect Pages Using Middleware</h2>
<p>Instead of using <code>getServerSession</code>, we can use middleware to protect routes and handle redirections. Create a middleware file in <code>src/middleware.ts</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;
<span class="hljs-keyword">import</span> { getToken } <span class="hljs-keyword">from</span> <span class="hljs-string">'next-auth/jwt'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">req</span>) </span>{
  <span class="hljs-keyword">const</span> token = <span class="hljs-keyword">await</span> getToken({ req, secret: process.env.NEXTAUTH_SECRET });
  <span class="hljs-keyword">const</span> { pathname } = req.nextUrl;

  <span class="hljs-comment">// Allow access to public paths</span>
  <span class="hljs-keyword">if</span> (pathname.startsWith(<span class="hljs-string">'/api/auth'</span>) || pathname === <span class="hljs-string">'/signin'</span>) {
    <span class="hljs-keyword">return</span> NextResponse.next();
  }

  <span class="hljs-comment">// Redirect if no token is found</span>
  <span class="hljs-keyword">if</span> (!token) {
    <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/signin'</span>, req.url));
  }

  <span class="hljs-keyword">return</span> NextResponse.next();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  matcher: [
    <span class="hljs-string">'/protected/:path*'</span>, <span class="hljs-comment">// Protect paths that start with /protected</span>
  ],
};
</code></pre>
<p>This middleware checks for a valid session token and redirects unauthenticated users to the sign-in page.</p>
<hr />
<h2 id="heading-step-5-add-the-sign-in-and-sign-out-components">Step 5: Add the Sign-In and Sign-Out Components</h2>
<p>To allow users to sign in and out, create a simple component using NextAuth.js hooks:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useSession, signIn, signOut } <span class="hljs-keyword">from</span> <span class="hljs-string">'next-auth/react'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AuthButton</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data: session } = useSession();

  <span class="hljs-keyword">if</span> (session) {
    <span class="hljs-keyword">return</span> (
      &lt;&gt;
        &lt;p&gt;Signed <span class="hljs-keyword">in</span> <span class="hljs-keyword">as</span> {session.user.email}&lt;/p&gt;
        &lt;button onClick={<span class="hljs-function">() =&gt;</span> signOut()}&gt;Sign Out&lt;/button&gt;
      &lt;/&gt;
    );
  }

  <span class="hljs-keyword">return</span> &lt;button onClick={<span class="hljs-function">() =&gt;</span> signIn()}&gt;Sign In&lt;/button&gt;;
}
</code></pre>
<hr />
<h2 id="heading-step-6-customize-the-authentication-flow-optional">Step 6: Customize the Authentication Flow (Optional)</h2>
<p>You can customize the authentication flow by modifying the <code>pages</code> property in the NextAuth.js configuration:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> NextAuth({
  pages: {
    signIn: <span class="hljs-string">'/auth/signin'</span>,
    signOut: <span class="hljs-string">'/auth/signout'</span>,
    error: <span class="hljs-string">'/auth/error'</span>,
    verifyRequest: <span class="hljs-string">'/auth/verify-request'</span>,
    newUser: <span class="hljs-string">'/auth/new-user'</span>,
  },
});
</code></pre>
<p>Create the corresponding pages in the <code>src/pages/auth</code> directory to match the paths defined above.</p>
<hr />
<h2 id="heading-benefits-of-using-middleware-for-authentication">Benefits of Using Middleware for Authentication</h2>
<ol>
<li><p><strong>Centralized Logic:</strong> Middleware handles authentication at the route level, simplifying server-side logic.</p>
</li>
<li><p><strong>Performance:</strong> Only restricted pages trigger session validation.</p>
</li>
<li><p><strong>Flexibility:</strong> Easily configure protected and public routes.</p>
</li>
</ol>
<hr />
<h2 id="heading-additional-resources-for-nextauthjs">Additional Resources for NextAuth.js</h2>
<p>To dive deeper into NextAuth.js and related topics, explore the following resources:</p>
<ol>
<li><p><a target="_blank" href="https://next-auth.js.org/getting-started/example">NextAuth.js Documentation</a> - Official documentation with detailed guides and examples.</p>
</li>
<li><p><a target="_blank" href="https://nextjs.org/learn/dashboard-app/adding-authentication">Securing Next.js Applications</a> - Learn more about authentication strategies in Next.js.</p>
</li>
</ol>
<p>These links provide additional insights and examples to help you expand your knowledge and make the most of NextAuth.js in your projects.</p>
]]></content:encoded></item><item><title><![CDATA[Integrating Tailwind CSS with Next.js]]></title><description><![CDATA[Tailwind CSS is a utility-first CSS framework that provides a flexible and efficient way to style your applications. Combining Tailwind CSS with Next.js allows developers to build beautiful and responsive user interfaces quickly. This guide walks you...]]></description><link>https://blogs.ishav.space/integrating-tailwind-css-with-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/integrating-tailwind-css-with-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Tailwind CSS]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sun, 05 Jan 2025 12:37:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736080627607/c087cfdd-e0be-4dbb-9efd-203d4a748196.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Tailwind CSS is a utility-first CSS framework that provides a flexible and efficient way to style your applications. Combining Tailwind CSS with Next.js allows developers to build beautiful and responsive user interfaces quickly. This guide walks you through the step-by-step process of integrating Tailwind CSS into a Next.js project.</p>
<hr />
<h2 id="heading-step-1-create-a-new-nextjs-project">Step 1: Create a New Next.js Project</h2>
<p>If you don’t have an existing Next.js project, start by creating one:</p>
<pre><code class="lang-bash">npx create-next-app@latest my-next-app
<span class="hljs-built_in">cd</span> my-next-app
</code></pre>
<p>Ensure you have Node.js and npm installed on your system before proceeding.</p>
<hr />
<h2 id="heading-step-2-install-tailwind-css">Step 2: Install Tailwind CSS</h2>
<p>Tailwind CSS can be installed via npm. Run the following commands to install Tailwind CSS and its dependencies:</p>
<pre><code class="lang-bash">npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
</code></pre>
<p>The <code>npx tailwindcss init</code> command generates a <code>tailwind.config.js</code> file in your project root. This file is used to configure Tailwind CSS.</p>
<hr />
<h2 id="heading-step-3-configure-tailwind-css">Step 3: Configure Tailwind CSS</h2>
<p>Edit the <code>tailwind.config.js</code> file to include the paths to your Next.js pages and components. This enables Tailwind to purge unused styles in production, ensuring optimal performance.</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  content: [
    <span class="hljs-string">"./src/pages/**/*.{js,ts,jsx,tsx}"</span>,
    <span class="hljs-string">"./src/components/**/*.{js,ts,jsx,tsx}"</span>,
    <span class="hljs-string">"./src/app/**/*.{js,ts,jsx,tsx}"</span>
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};
</code></pre>
<hr />
<h2 id="heading-step-4-add-tailwind-directives-to-css">Step 4: Add Tailwind Directives to CSS</h2>
<p>Create a global CSS file if it doesn’t already exist, typically in <code>src/app/globals.css</code>. Add the following Tailwind directives to the file:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p>Ensure this file is imported into your Next.js application, usually in the <code>layout.tsx</code> file:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-string">'./globals.css'</span>;
</code></pre>
<hr />
<h2 id="heading-step-5-start-the-development-server">Step 5: Start the Development Server</h2>
<p>Run the development server to check if Tailwind CSS is working correctly:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Open your browser and navigate to <code>http://localhost:3000</code>. Use Tailwind’s utility classes in your components to verify integration.</p>
<h3 id="heading-example">Example:</h3>
<p>Edit <code>src/app/page.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomePage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"flex items-center justify-center min-h-screen bg-gray-100"</span>&gt;
      &lt;h1 className=<span class="hljs-string">"text-4xl font-bold text-blue-500"</span>&gt;
        Welcome to Next.js <span class="hljs-keyword">with</span> Tailwind CSS!
      &lt;/h1&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-step-6-customize-tailwind-configuration-optional">Step 6: Customize Tailwind Configuration (Optional)</h2>
<p>You can extend the default Tailwind theme to include custom colors, spacing, fonts, or other design tokens.</p>
<p>Example:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  theme: {
    extend: {
      colors: {
        customBlue: <span class="hljs-string">'#1e3a8a'</span>,
      },
    },
  },
};
</code></pre>
<p>Use the custom color in your application:</p>
<pre><code class="lang-typescript">&lt;div className=<span class="hljs-string">"bg-customBlue text-white p-4"</span>&gt;
  Custom Tailwind Color!
&lt;/div&gt;
</code></pre>
<hr />
<h2 id="heading-step-7-add-plugins-optional">Step 7: Add Plugins (Optional)</h2>
<p>Tailwind CSS has a wide range of plugins that add additional functionality, such as forms, typography, and aspect ratios.</p>
<p>Install a plugin:</p>
<pre><code class="lang-bash">npm install -D @tailwindcss/forms
</code></pre>
<p>Update <code>tailwind.config.js</code> to include the plugin:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  plugins: [
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'@tailwindcss/forms'</span>),
  ],
};
</code></pre>
<hr />
<h2 id="heading-benefits-of-using-tailwind-css-with-nextjs">Benefits of Using Tailwind CSS with Next.js</h2>
<ul>
<li><p><strong>Rapid Development:</strong> Build interfaces faster with pre-defined utility classes.</p>
</li>
<li><p><strong>Responsive Design:</strong> Tailwind’s responsive utilities make it easy to create mobile-friendly designs.</p>
</li>
<li><p><strong>Customizable:</strong> Extend the framework to fit your design system.</p>
</li>
<li><p><strong>Performance:</strong> Automatically removes unused styles in production builds.</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Integrating Tailwind CSS with Next.js empowers developers to create visually appealing and performant applications with minimal effort. By following this guide, you can quickly set up and start styling your Next.js project. Explore Tailwind’s extensive documentation to unlock its full potential!</p>
]]></content:encoded></item><item><title><![CDATA[How to Optimize Images in Next.js]]></title><description><![CDATA[Images play a critical role in web performance and user experience. Next.js provides a built-in solution for image optimization with the next/image component. This guide explores how to use next/image effectively to achieve faster load times and impr...]]></description><link>https://blogs.ishav.space/how-to-optimize-images-in-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/how-to-optimize-images-in-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[next/image]]></category><category><![CDATA[image processing]]></category><category><![CDATA[lazy loading]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sat, 04 Jan 2025 11:58:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735991812615/92fcc532-df8c-4326-98e0-65ba75cf8d35.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Images play a critical role in web performance and user experience. Next.js provides a built-in solution for image optimization with the <code>next/image</code> component. This guide explores how to use <code>next/image</code> effectively to achieve faster load times and improved performance.</p>
<hr />
<h2 id="heading-why-optimize-images">Why Optimize Images?</h2>
<p>Optimized images reduce page load times, enhance user experience, and improve SEO rankings. Without optimization, images can:</p>
<ul>
<li><p>Increase the total page size.</p>
</li>
<li><p>Slow down loading times.</p>
</li>
<li><p>Negatively impact performance metrics like LCP (Largest Contentful Paint).</p>
</li>
</ul>
<p>Next.js handles these issues seamlessly with the <code>next/image</code> component.</p>
<hr />
<h2 id="heading-introducing-the-nextimage-component">Introducing the <code>next/image</code> Component</h2>
<p>The <code>next/image</code> component provides automatic optimization for images. Key features include:</p>
<ul>
<li><p><strong>Responsive Loading:</strong> Automatically adjusts image size based on the viewport.</p>
</li>
<li><p><strong>Lazy Loading:</strong> Only loads images when they are visible on the screen.</p>
</li>
<li><p><strong>Formats:</strong> Automatically serves modern formats like WebP if supported by the browser.</p>
</li>
</ul>
<h3 id="heading-basic-usage">Basic Usage</h3>
<p>Here’s how to use the <code>next/image</code> component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">'next/image'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomePage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Welcome to Next.js Image Optimization&lt;/h1&gt;
      &lt;Image
        src=<span class="hljs-string">"/example.jpg"</span>
        alt=<span class="hljs-string">"Example Image"</span>
        width={<span class="hljs-number">800</span>}
        height={<span class="hljs-number">600</span>}
      /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<h3 id="heading-output">Output</h3>
<ul>
<li><p>The image is resized to 800x600 pixels.</p>
</li>
<li><p>It’s optimized for responsive layouts.</p>
</li>
<li><p>Lazy loading is enabled by default.</p>
</li>
</ul>
<hr />
<h2 id="heading-advanced-features">Advanced Features</h2>
<h3 id="heading-1-responsive-images">1. Responsive Images</h3>
<p>To make images responsive, use the <code>layout</code> property:</p>
<pre><code class="lang-typescript">&lt;Image
  src=<span class="hljs-string">"/example.jpg"</span>
  alt=<span class="hljs-string">"Responsive Image"</span>
  layout=<span class="hljs-string">"responsive"</span>
  width={<span class="hljs-number">16</span>}
  height={<span class="hljs-number">9</span>}
/&gt;
</code></pre>
<p>This ensures the image maintains a 16:9 aspect ratio while adjusting to the viewport size.</p>
<h3 id="heading-2-lazy-loading">2. Lazy Loading</h3>
<p>Lazy loading is enabled by default. However, you can customize it using the <code>loading</code> property:</p>
<pre><code class="lang-typescript">&lt;Image
  src=<span class="hljs-string">"/example.jpg"</span>
  alt=<span class="hljs-string">"Lazy Loaded Image"</span>
  width={<span class="hljs-number">800</span>}
  height={<span class="hljs-number">600</span>}
  loading=<span class="hljs-string">"eager"</span>
/&gt;
</code></pre>
<h3 id="heading-3-priority-loading">3. Priority Loading</h3>
<p>For above-the-fold images, use the <code>priority</code> attribute to preload them:</p>
<pre><code class="lang-typescript">&lt;Image
  src=<span class="hljs-string">"/hero.jpg"</span>
  alt=<span class="hljs-string">"Hero Image"</span>
  width={<span class="hljs-number">1200</span>}
  height={<span class="hljs-number">800</span>}
  priority
/&gt;
</code></pre>
<h3 id="heading-4-external-images">4. External Images</h3>
<p>To use images hosted on external URLs, update the <code>next.config.js</code> file:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  images: {
    domains: [<span class="hljs-string">'example.com'</span>],
  },
};
</code></pre>
<p>Then use the <code>next/image</code> component:</p>
<pre><code class="lang-typescript">&lt;Image
  src=<span class="hljs-string">"https://example.com/external-image.jpg"</span>
  alt=<span class="hljs-string">"External Image"</span>
  width={<span class="hljs-number">800</span>}
  height={<span class="hljs-number">600</span>}
/&gt;
</code></pre>
<h3 id="heading-5-custom-loaders">5. Custom Loaders</h3>
<p>For advanced use cases, you can define a custom loader:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> myLoader = <span class="hljs-function">(<span class="hljs-params">{ src, width, quality }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">`https://example.com/<span class="hljs-subst">${src}</span>?w=<span class="hljs-subst">${width}</span>&amp;q=<span class="hljs-subst">${quality || <span class="hljs-number">75</span>}</span>`</span>;
};

&lt;Image
  loader={myLoader}
  src=<span class="hljs-string">"example.jpg"</span>
  alt=<span class="hljs-string">"Custom Loader Image"</span>
  width={<span class="hljs-number">800</span>}
  height={<span class="hljs-number">600</span>}
/&gt;
</code></pre>
<hr />
<h2 id="heading-image-formats-and-quality">Image Formats and Quality</h2>
<ul>
<li><p><strong>Formats:</strong> Next.js automatically serves WebP when supported.</p>
</li>
<li><p><strong>Quality:</strong> Adjust image quality using the <code>quality</code> property:</p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;Image
  src=<span class="hljs-string">"/example.jpg"</span>
  alt=<span class="hljs-string">"High Quality Image"</span>
  width={<span class="hljs-number">800</span>}
  height={<span class="hljs-number">600</span>}
  quality={<span class="hljs-number">90</span>}
/&gt;
</code></pre>
<hr />
<h2 id="heading-common-use-cases">Common Use Cases</h2>
<h3 id="heading-1-hero-banners">1. Hero Banners</h3>
<pre><code class="lang-typescript">&lt;Image
  src=<span class="hljs-string">"/hero-banner.jpg"</span>
  alt=<span class="hljs-string">"Hero Banner"</span>
  layout=<span class="hljs-string">"fill"</span>
  objectFit=<span class="hljs-string">"cover"</span>
  priority
/&gt;
</code></pre>
<h3 id="heading-2-gallery">2. Gallery</h3>
<pre><code class="lang-typescript">&lt;div className=<span class="hljs-string">"gallery"</span>&gt;
  {[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>].map(<span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> (
    &lt;Image
      key={id}
      src={<span class="hljs-string">`/gallery/image-<span class="hljs-subst">${id}</span>.jpg`</span>}
      alt={<span class="hljs-string">`Gallery Image <span class="hljs-subst">${id}</span>`</span>}
      width={<span class="hljs-number">300</span>}
      height={<span class="hljs-number">200</span>}
    /&gt;
  ))}
&lt;/div&gt;
</code></pre>
<hr />
<h2 id="heading-benefits-of-using-nextimage">Benefits of Using <code>next/image</code></h2>
<ul>
<li><p><strong>Improved Performance:</strong> Automatic optimization and lazy loading.</p>
</li>
<li><p><strong>SEO-Friendly:</strong> Enhanced performance scores for better rankings.</p>
</li>
<li><p><strong>Developer Convenience:</strong> Simplified API for managing images.</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Optimizing images is essential for a fast and efficient web experience. The <code>next/image</code> component simplifies the process with responsive loading, lazy loading, and modern formats. By leveraging these features, you can enhance both user experience and SEO performance. Start optimizing your images today to unlock the full potential of Next.js!</p>
]]></content:encoded></item><item><title><![CDATA[Dynamic Routing and Catch-All Routes in Next.js]]></title><description><![CDATA[Dynamic routing in Next.js allows you to create flexible routes that adapt to user input. This feature is particularly useful for building dynamic applications like blogs, e-commerce sites, and user-specific dashboards. Additionally, Next.js provides...]]></description><link>https://blogs.ishav.space/dynamic-routing-and-catch-all-routes-in-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/dynamic-routing-and-catch-all-routes-in-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[ChaiCode]]></category><category><![CDATA[routing]]></category><category><![CDATA[Dynamic Routing]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Tue, 31 Dec 2024 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735821960404/356f4324-359e-4e4d-806e-a539e3575d36.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Dynamic routing in Next.js allows you to create flexible routes that adapt to user input. This feature is particularly useful for building dynamic applications like blogs, e-commerce sites, and user-specific dashboards. Additionally, Next.js provides robust support for handling non-existent routes through custom 404 pages and catch-all routes.</p>
<hr />
<h2 id="heading-what-is-dynamic-routing">What is Dynamic Routing?</h2>
<p>Dynamic routing enables you to define routes where part of the URL can change dynamically. For example:</p>
<ul>
<li><code>/product/[id]</code> can match URLs like <code>/product/1</code>, <code>/product/2</code> or <code>/product/special-item</code>.</li>
</ul>
<hr />
<h2 id="heading-difference-between-nextnavigation-and-nextrouter">Difference Between <code>next/navigation</code> and <code>next/router</code></h2>
<p>Both <code>next/navigation</code> and <code>next/router</code> offer routing utilities, but they cater to different environments within Next.js.</p>
<h3 id="heading-nextnavigation"><code>next/navigation</code></h3>
<ul>
<li><p><strong>Scope</strong>: Specifically designed for the App Router (introduced in Next.js 13).</p>
</li>
<li><p><strong>Features</strong>:</p>
<ul>
<li><p><code>useParams</code>: Access dynamic route parameters.</p>
</li>
<li><p><code>useSearchParams</code>: Access query parameters.</p>
</li>
<li><p><code>useRouter</code>: Provides navigation methods like <code>push</code>, <code>replace</code>, and <code>back</code>.</p>
</li>
<li><p><code>notFound</code>: Programmatically trigger 404 pages.</p>
</li>
<li><p><code>redirect</code>: Redirect users to a specific URL.</p>
</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>Recommended Use</strong>: When using the App Router for building routes in the <code>src/app</code> directory.</p>
</blockquote>
<h3 id="heading-nextrouter"><code>next/router</code></h3>
<ul>
<li><p><strong>Scope</strong>: Designed for the Pages Router (traditional routing system in Next.js).</p>
</li>
<li><p><strong>Features</strong>:</p>
<ul>
<li><p><code>useRouter</code>: Access the router object for navigation and dynamic route handling.</p>
</li>
<li><p><code>query</code>: Access route parameters and query strings.</p>
</li>
<li><p><code>prefetch</code>: Prefetch pages for better performance.</p>
</li>
</ul>
</li>
<li><p><strong>Recommended Use</strong>: When building applications in the <code>src/pages</code> directory.</p>
</li>
</ul>
<hr />
<h2 id="heading-creating-dynamic-routes">Creating Dynamic Routes</h2>
<h3 id="heading-step-1-define-a-dynamic-route-file">Step 1: Define a Dynamic Route File</h3>
<p>To create a dynamic route, use square brackets (<code>[ ]</code>) in your file or folder name within the <code>pages</code> or <code>app</code> directory. For example:</p>
<pre><code class="lang-plaintext">src/app/products/[id]/page.tsx
</code></pre>
<h3 id="heading-step-2-access-the-dynamic-parameter">Step 2: Access the Dynamic Parameter</h3>
<p>Inside your dynamic route, you can access the parameter using <code>params</code> (in the App Router) or <code>query</code> (in the Pages Router).</p>
<h4 id="heading-app-router-example">App Router Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> ProductPageProps {
  params: { id: <span class="hljs-built_in">string</span> };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductPage</span>(<span class="hljs-params">{ params }: ProductPageProps</span>) </span>{
  <span class="hljs-keyword">return</span> &lt;h1&gt;Product ID: {params.id}&lt;/h1&gt;;
}
</code></pre>
<h4 id="heading-pages-router-example">Pages Router Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/router'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> { id } = router.query;

  <span class="hljs-keyword">return</span> &lt;h1&gt;Product ID: {id}&lt;/h1&gt;;
}
</code></pre>
<p>Inside your dynamic route, you can access the parameter using the <code>params</code> object provided by Next.js.</p>
<h4 id="heading-example-using-app-router">Example Using App Router:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { notFound } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/navigation'</span>;

<span class="hljs-keyword">interface</span> ProductPageProps {
  params: { id: <span class="hljs-built_in">string</span> };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductPage</span>(<span class="hljs-params">{ params }: ProductPageProps</span>) </span>{
  <span class="hljs-keyword">if</span> (!params.id) {
    notFound();
  }

  <span class="hljs-keyword">return</span> &lt;h1&gt;Product ID: {params.id}&lt;/h1&gt;;
}
</code></pre>
<p>Alternatively, use the <code>useParams</code> hook from <code>next/navigation</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useParams } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/navigation'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> params = useParams();

  <span class="hljs-keyword">if</span> (!params.id) {
    <span class="hljs-keyword">return</span> &lt;h1&gt;<span class="hljs-number">404</span> - Product Not Found&lt;/h1&gt;;
  }

  <span class="hljs-keyword">return</span> &lt;h1&gt;Product ID: {params.id}&lt;/h1&gt;;
}
</code></pre>
<hr />
<h2 id="heading-catch-all-routes">Catch-All Routes</h2>
<p>Catch-all routes match multiple URL segments and are defined using <code>[...param]</code> in the file or folder name.</p>
<h3 id="heading-example">Example:</h3>
<pre><code class="lang-plaintext">src/app/docs/[...slug]/page.tsx
</code></pre>
<h4 id="heading-handling-catch-all-parameters">Handling Catch-All Parameters:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> DocsPageProps {
  params: { slug: <span class="hljs-built_in">string</span>[] };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DocsPage</span>(<span class="hljs-params">{ params }: DocsPageProps</span>) </span>{
  <span class="hljs-keyword">const</span> slugPath = params.slug.join(<span class="hljs-string">'/'</span>);

  <span class="hljs-keyword">return</span> &lt;h1&gt;Viewing: {slugPath}&lt;/h1&gt;;
}
</code></pre>
<p>This route will match paths like:</p>
<ul>
<li><p><code>/docs</code></p>
</li>
<li><p><code>/docs/getting-started</code></p>
</li>
<li><p><code>/docs/tutorials/advanced</code></p>
</li>
</ul>
<hr />
<h2 id="heading-optional-catch-all-routes">Optional Catch-All Routes</h2>
<p>You can make a catch-all route optional by adding a question mark (<code>?</code>) in the file name:</p>
<p>This matches both <code>/docs</code> and any nested paths under <code>/docs</code>.</p>
<p>By adding a question mark (<code>?</code>) after the <code>...slug</code> part, you can make the catch-all segment optional, meaning the route will match even if there's no additional path segment after the base URL.</p>
<pre><code class="lang-plaintext">pages/docs/[...slug]?
This route will match:
- /docs
- /docs/post-title
- /docs/category/article-name
</code></pre>
<ul>
<li><p><strong>Usage:</strong></p>
<p>  This is particularly useful for creating fallback pages or handling situations where a user might access a URL with or without additional parameters.</p>
</li>
</ul>
<hr />
<h2 id="heading-handling-404-errors">Handling 404 Errors</h2>
<p>Next.js allows you to create a custom 404 page for non-existent routes.</p>
<h3 id="heading-step-1-create-a-404-page">Step 1: Create a <code>404</code> Page</h3>
<p>In the App Router:</p>
<pre><code class="lang-plaintext">src/app/not-found.tsx
</code></pre>
<p>In the Pages Router:</p>
<pre><code class="lang-plaintext">src/pages/404.tsx
</code></pre>
<h3 id="heading-step-2-define-the-custom-404-page">Step 2: Define the Custom 404 Page</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">NotFound</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> &lt;h1&gt;<span class="hljs-number">404</span> - Page Not Found&lt;/h1&gt;;
}
</code></pre>
<p>With the App Router, you can also use the <code>notFound()</code> function to programmatically trigger a 404:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { notFound } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/navigation'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductPage</span>(<span class="hljs-params">{ params }: { params: { id: <span class="hljs-built_in">string</span> } }</span>) </span>{
  <span class="hljs-keyword">if</span> (!params.id) {
    notFound();
  }

  <span class="hljs-keyword">return</span> &lt;h1&gt;Product ID: {params.id}&lt;/h1&gt;;
}
</code></pre>
<hr />
<h2 id="heading-practical-use-cases">Practical Use Cases</h2>
<ol>
<li><p><strong>Blogs</strong>:</p>
<ul>
<li><code>/blog/[slug]</code> for articles with unique slugs.</li>
</ul>
</li>
<li><p><strong>E-Commerce</strong>:</p>
<ul>
<li><code>/products/[id]</code> for individual product pages.</li>
</ul>
</li>
<li><p><strong>Documentation</strong>:</p>
<ul>
<li><code>/docs/[...slug]</code> for structured documentation paths.</li>
</ul>
</li>
<li><p><strong>Custom 404 Pages</strong>:</p>
<ul>
<li>Enhance user experience with branded 404 pages.</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Dynamic and catch-all routes in Next.js provide a flexible and powerful way to build dynamic applications. By understanding how to create and use these routes effectively, you can handle a wide variety of use cases, from user-specific pages to structured documentation paths. Start exploring dynamic routing today to unlock the full potential of your Next.js applications!</p>
]]></content:encoded></item><item><title><![CDATA[Using Middleware in Next.js]]></title><description><![CDATA[Middleware in Next.js allows you to run code before a request is completed. It’s a powerful tool for tasks like authentication, logging, redirects, and more. With middleware, you can enhance your application’s behavior on both server-side and edge fu...]]></description><link>https://blogs.ishav.space/using-middleware-in-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/using-middleware-in-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Middleware]]></category><category><![CDATA[authentication]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sat, 28 Dec 2024 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735650311526/a0119583-76c8-4fdd-844b-1d7481801c1d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Middleware in Next.js allows you to run code before a request is completed. It’s a powerful tool for tasks like authentication, logging, redirects, and more. With middleware, you can enhance your application’s behavior on both server-side and edge functions, improving performance and user experience.</p>
<hr />
<h2 id="heading-what-is-middleware-in-nextjs">What is Middleware in Next.js?</h2>
<p>Middleware is a function that executes during the request lifecycle. It allows you to modify the request or response before it reaches its destination.</p>
<h3 id="heading-key-features">Key Features:</h3>
<ul>
<li><p><strong>Runs on Edge</strong>: Middleware executes on Vercel’s Edge Network for optimal performance.</p>
</li>
<li><p><strong>Dynamic Control</strong>: Modify responses, redirect users, or authenticate requests dynamically.</p>
</li>
<li><p><strong>File-Based</strong>: Like routes, middleware is file-based.</p>
</li>
</ul>
<hr />
<h2 id="heading-creating-your-first-middleware">Creating Your First Middleware</h2>
<h3 id="heading-step-1-add-a-middleware-file">Step 1: Add a Middleware File</h3>
<p>Middleware is defined in a <code>middleware.ts</code> file at the root of your <code>src</code> directory.</p>
<pre><code class="lang-plaintext">src/middleware.ts
</code></pre>
<h3 id="heading-step-2-define-your-middleware-logic">Step 2: Define Your Middleware Logic</h3>
<p>Here’s an example of middleware that redirects users who are not logged in to a login page:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { NextRequest, NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">request: NextRequest</span>) </span>{
  <span class="hljs-keyword">const</span> isAuthenticated = request.cookies.get(<span class="hljs-string">'auth-token'</span>);

  <span class="hljs-keyword">if</span> (!isAuthenticated) {
    <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/login'</span>, request.url));
  }

  <span class="hljs-keyword">return</span> NextResponse.next();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  matcher: [<span class="hljs-string">'/dashboard/:path*'</span>], <span class="hljs-comment">// Apply middleware to specific routes</span>
};
</code></pre>
<h3 id="heading-explanation">Explanation:</h3>
<ul>
<li><p><code>NextRequest</code>: Represents the incoming request.</p>
</li>
<li><p><code>NextResponse</code>: Used to send responses like redirects or modifications.</p>
</li>
<li><p><code>matcher</code>: Specifies the routes where the middleware should apply.</p>
</li>
</ul>
<hr />
<h2 id="heading-use-case-authentication-middleware">Use Case: Authentication Middleware</h2>
<p>One common use case for middleware is protecting routes that require authentication.</p>
<h3 id="heading-example">Example:</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { NextRequest, NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">request: NextRequest</span>) </span>{
  <span class="hljs-keyword">const</span> token = request.cookies.get(<span class="hljs-string">'auth-token'</span>);

  <span class="hljs-keyword">if</span> (!token) {
    <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/signin'</span>, request.url));
  }

  <span class="hljs-keyword">return</span> NextResponse.next();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  matcher: [<span class="hljs-string">'/profile/:path*'</span>, <span class="hljs-string">'/settings/:path*'</span>],
};
</code></pre>
<ul>
<li><p>If the <code>auth-token</code> cookie is missing, the user is redirected to the <code>/signin</code> page.</p>
</li>
<li><p>Middleware is applied to routes like <code>/profile</code> and <code>/settings</code>.</p>
</li>
</ul>
<hr />
<h2 id="heading-use-case-redirect-middleware">Use Case: Redirect Middleware</h2>
<p>You can use middleware to dynamically redirect users based on conditions, such as locale or device type.</p>
<h3 id="heading-example-1">Example:</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { NextRequest, NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">request: NextRequest</span>) </span>{
  <span class="hljs-keyword">const</span> country = request.geo?.country || <span class="hljs-string">'US'</span>;

  <span class="hljs-keyword">if</span> (country === <span class="hljs-string">'FR'</span>) {
    <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/fr'</span>, request.url));
  }

  <span class="hljs-keyword">return</span> NextResponse.next();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  matcher: [<span class="hljs-string">'/'</span>],
};
</code></pre>
<ul>
<li><p><code>request.geo</code>: Provides geolocation information.</p>
</li>
<li><p>Users from France (<code>FR</code>) are redirected to a localized <code>/fr</code> page.</p>
</li>
</ul>
<hr />
<h2 id="heading-debugging-middleware">Debugging Middleware</h2>
<p>To debug your middleware, use <code>console.log()</code> statements. However, remember that middleware runs on the Edge, so logs appear in the Vercel dashboard or terminal during local development.</p>
<hr />
<h2 id="heading-limitations-of-middleware">Limitations of Middleware</h2>
<ul>
<li><p>Middleware does not have access to environment variables.</p>
</li>
<li><p>Middleware cannot fetch data from APIs.</p>
</li>
<li><p>Middleware runs before static files are served, so it won’t apply to images or other public assets.</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Middleware in Next.js provides a versatile way to handle authentication, redirection, and more. By running code before requests are completed, you can enhance your app’s functionality and user experience. Start experimenting with middleware today to see how it can streamline your Next.js applications!</p>
]]></content:encoded></item><item><title><![CDATA[Deploying a Next.js App on Vercel]]></title><description><![CDATA[Deploying your Next.js app on Vercel is simple and beginner-friendly. As the creators of Next.js, Vercel provides seamless integration, optimized performance, and an easy-to-use platform for hosting your applications. This guide will walk you through...]]></description><link>https://blogs.ishav.space/deploying-a-nextjs-app-on-vercel</link><guid isPermaLink="true">https://blogs.ishav.space/deploying-a-nextjs-app-on-vercel</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Vercel]]></category><category><![CDATA[deployment]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Sat, 28 Dec 2024 12:48:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735390053747/0ad15c49-1f94-43f1-9149-56d4e96a21dc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Deploying your Next.js app on Vercel is simple and beginner-friendly. As the creators of Next.js, Vercel provides seamless integration, optimized performance, and an easy-to-use platform for hosting your applications. This guide will walk you through the steps to deploy your Next.js project on Vercel.</p>
<hr />
<h2 id="heading-why-choose-vercel-for-nextjs">Why Choose Vercel for Next.js?</h2>
<p>Vercel is the recommended hosting platform for Next.js due to its:</p>
<ul>
<li><p><strong>One-Click Deployment</strong>: Quickly deploy your app directly from your Git repository.</p>
</li>
<li><p><strong>Serverless Functions</strong>: Automatically handle API routes as serverless functions.</p>
</li>
<li><p><strong>Automatic Scaling</strong>: Effortless scaling without manual configuration.</p>
</li>
<li><p><strong>Optimized Performance</strong>: Built-in CDN and image optimization for faster load times.</p>
</li>
</ul>
<hr />
<h2 id="heading-step-by-step-guide-to-deploying-a-nextjs-app">Step-by-Step Guide to Deploying a Next.js App</h2>
<h3 id="heading-1-prepare-your-nextjs-project">1. Prepare Your Next.js Project</h3>
<p>Ensure your project is ready for deployment:</p>
<ul>
<li>Create a Next.js project if you haven’t already:</li>
</ul>
<pre><code class="lang-bash">npx create-next-app@latest my-next-app
<span class="hljs-built_in">cd</span> my-next-app
</code></pre>
<ul>
<li>Test your app locally:</li>
</ul>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>If your app runs without issues, proceed to the next step.</p>
<hr />
<h3 id="heading-2-push-your-code-to-github-or-gitlabbitbucket">2. Push Your Code to GitHub (or GitLab/Bitbucket)</h3>
<ol>
<li><strong>Initialize a Git Repository</strong>:</li>
</ol>
<pre><code class="lang-bash">git init
git add .
git commit -m <span class="hljs-string">"first commit"</span>
</code></pre>
<ol start="2">
<li><p><strong>Create a Remote Repository</strong>:</p>
<ul>
<li><p>Go to GitHub and create a new repository.</p>
</li>
<li><p>Copy the repository URL.</p>
</li>
</ul>
</li>
<li><p><strong>Push Your Code</strong>:</p>
</li>
</ol>
<pre><code class="lang-bash">git remote add origin &lt;your-repository-url&gt;
git branch -M main
git push -u origin main
</code></pre>
<hr />
<h3 id="heading-3-sign-up-or-log-in-to-vercel">3. Sign Up or Log In to Vercel</h3>
<ol>
<li><p>Visit <a target="_blank" href="https://vercel.com">Vercel's website</a>.</p>
</li>
<li><p>Sign up using GitHub, GitLab, or Bitbucket.</p>
</li>
<li><p>After signing in, you’ll be redirected to the Vercel dashboard.</p>
</li>
</ol>
<hr />
<h3 id="heading-4-import-your-project-to-vercel">4. Import Your Project to Vercel</h3>
<ol>
<li><p>Click on the <strong>"New Project"</strong> button in your Vercel dashboard.</p>
</li>
<li><p>Select your Git provider (GitHub, GitLab, or Bitbucket).</p>
</li>
<li><p>Find your repository in the list and click <strong>"Import"</strong>.</p>
</li>
</ol>
<hr />
<h3 id="heading-5-configure-your-deployment-settings">5. Configure Your Deployment Settings</h3>
<ol>
<li><p><strong>Build and Output Settings</strong>:</p>
<ul>
<li><p>Vercel automatically detects your Next.js framework.</p>
</li>
<li><p>Ensure the following settings are configured:</p>
<ul>
<li><p><strong>Framework Preset</strong>: Next.js</p>
</li>
<li><p><strong>Build Command</strong>: <code>npm run build</code></p>
</li>
<li><p><strong>Output Directory</strong>: <code>.next</code></p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Environment Variables</strong> (Optional):</p>
<ul>
<li>Add any necessary environment variables for your app.</li>
</ul>
</li>
<li><p>Click <strong>"Deploy"</strong> to start the deployment process.</p>
</li>
</ol>
<hr />
<h3 id="heading-6-monitor-the-deployment-process">6. Monitor the Deployment Process</h3>
<p>Vercel will:</p>
<ul>
<li><p>Clone your repository.</p>
</li>
<li><p>Install dependencies.</p>
</li>
<li><p>Build your project.</p>
</li>
<li><p>Deploy the app to their servers.</p>
</li>
</ul>
<p>Once the process is complete, you’ll receive a live URL to your deployed app (e.g., <code>https://your-app.vercel.app</code>).</p>
<hr />
<h3 id="heading-7-verify-your-deployment">7. Verify Your Deployment</h3>
<ol>
<li><p>Open the provided URL to see your live app.</p>
</li>
<li><p>Test all features to ensure everything works as expected.</p>
</li>
</ol>
<hr />
<h2 id="heading-advanced-features-on-vercel">Advanced Features on Vercel</h2>
<h3 id="heading-custom-domains">Custom Domains</h3>
<ul>
<li><p>Add a custom domain from the <strong>"Domains"</strong> section in your Vercel dashboard.</p>
</li>
<li><p>Configure DNS settings to point to Vercel.</p>
</li>
</ul>
<h3 id="heading-automatic-deployments">Automatic Deployments</h3>
<ul>
<li>Every time you push changes to your Git repository, Vercel automatically redeploys your app.</li>
</ul>
<h3 id="heading-analytics">Analytics</h3>
<ul>
<li>Use Vercel’s built-in analytics to monitor your app’s performance and user interactions.</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Deploying a Next.js app on Vercel is quick, straightforward, and packed with features. By following this guide, you can have your app live in just a few minutes. With Vercel’s seamless integration and powerful hosting capabilities, you can focus on building great applications while Vercel takes care of the rest. Start deploying and share your Next.js creations with the world!</p>
]]></content:encoded></item><item><title><![CDATA[Building Your First API Route in Next.js]]></title><description><![CDATA[Next.js simplifies the process of building API routes by allowing you to create serverless functions directly within your app. These routes can handle various types of server-side logic, such as fetching data, processing forms, or integrating with th...]]></description><link>https://blogs.ishav.space/building-your-first-api-route-in-nextjs</link><guid isPermaLink="true">https://blogs.ishav.space/building-your-first-api-route-in-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[APIs]]></category><category><![CDATA[Postman]]></category><category><![CDATA[backend]]></category><category><![CDATA[backend developments]]></category><category><![CDATA[serverless]]></category><dc:creator><![CDATA[Strnge]]></dc:creator><pubDate>Wed, 25 Dec 2024 18:28:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735151324671/6e38fda9-ae37-42b2-9219-aa832ab5273d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Next.js simplifies the process of building API routes by allowing you to create serverless functions directly within your app. These routes can handle various types of server-side logic, such as fetching data, processing forms, or integrating with third-party APIs. Here's how to create your first API route in Next.js.</p>
<hr />
<h2 id="heading-what-are-api-routes-in-nextjs">What Are API Routes in Next.js?</h2>
<p>API routes in Next.js enable you to define backend endpoints as part of your Next.js application. These routes are serverless functions that run on demand, and they can be deployed alongside your frontend code.</p>
<h3 id="heading-key-features-of-api-routes">Key Features of API Routes:</h3>
<ul>
<li><p><strong>Ease of Use</strong>: API routes are simple to set up and live within your Next.js project.</p>
</li>
<li><p><strong>Serverless</strong>: Each route is deployed as a serverless function.</p>
</li>
<li><p><strong>Flexible</strong>: They can handle requests like GET, POST, PUT, DELETE, etc.</p>
</li>
</ul>
<hr />
<h2 id="heading-setting-up-your-first-api-route">Setting Up Your First API Route</h2>
<h3 id="heading-step-1-create-the-api-folder">Step 1: Create the <code>api</code> Folder</h3>
<p>In your project directory, navigate to the <code>src/app</code> folder (if you're using the <code>src</code> directory setup) or the <code>app</code> folder. Inside, create a folder named <code>api</code>.</p>
<pre><code class="lang-plaintext">src/app/api/
</code></pre>
<h3 id="heading-step-2-define-an-api-route">Step 2: Define an API Route</h3>
<p>Inside the <code>api</code> folder, create a file named <code>hello.ts</code>. This file will define a simple API endpoint.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/api/hello.ts</span>
<span class="hljs-keyword">import</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req: NextApiRequest, res: NextApiResponse</span>) </span>{
  res.status(<span class="hljs-number">200</span>).json({ message: <span class="hljs-string">'Hello, world!'</span> });
}
</code></pre>
<h3 id="heading-step-3-access-the-api-route">Step 3: Access the API Route</h3>
<p>Start your development server with:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Open your browser and navigate to <code>http://localhost:3000/api/hello</code>. You should see the following JSON response:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Hello, world!"</span>
}
</code></pre>
<hr />
<h2 id="heading-handling-different-http-methods">Handling Different HTTP Methods</h2>
<p>API routes in Next.js can handle multiple HTTP methods. Here’s how you can differentiate between them:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/api/greet.ts</span>
<span class="hljs-keyword">import</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req: NextApiRequest, res: NextApiResponse</span>) </span>{
  <span class="hljs-keyword">if</span> (req.method === <span class="hljs-string">'GET'</span>) {
    res.status(<span class="hljs-number">200</span>).json({ message: <span class="hljs-string">'This is a GET request'</span> });
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (req.method === <span class="hljs-string">'POST'</span>) {
    <span class="hljs-keyword">const</span> { name } = req.body;
    res.status(<span class="hljs-number">200</span>).json({ message: <span class="hljs-string">`Hello, <span class="hljs-subst">${name}</span>!`</span> });
  } <span class="hljs-keyword">else</span> {
    res.setHeader(<span class="hljs-string">'Allow'</span>, [<span class="hljs-string">'GET'</span>, <span class="hljs-string">'POST'</span>]);
    res.status(<span class="hljs-number">405</span>).end(<span class="hljs-string">`Method <span class="hljs-subst">${req.method}</span> Not Allowed`</span>);
  }
}
</code></pre>
<h3 id="heading-testing-the-api">Testing the API</h3>
<ul>
<li><p><strong>GET Request</strong>: Access <code>http://localhost:3000/api/greet</code> in your browser.</p>
</li>
<li><p><strong>POST Request</strong>: Use a tool like Postman or cURL to send a POST request with a JSON body:</p>
</li>
</ul>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>
}
</code></pre>
<p>Response:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Hello, John Doe!"</span>
}
</code></pre>
<hr />
<h2 id="heading-adding-query-parameters">Adding Query Parameters</h2>
<p>You can access query parameters from the request object using <code>req.query</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/api/user.ts</span>
<span class="hljs-keyword">import</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req: NextApiRequest, res: NextApiResponse</span>) </span>{
  <span class="hljs-keyword">const</span> { id } = req.query;
  res.status(<span class="hljs-number">200</span>).json({ message: <span class="hljs-string">`User ID is <span class="hljs-subst">${id}</span>`</span> });
}
</code></pre>
<p>Access the API route with a query parameter, e.g., <code>http://localhost:3000/api/user?id=123</code>, and you’ll get:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"message"</span>: <span class="hljs-string">"User ID is 123"</span>
}
</code></pre>
<hr />
<h2 id="heading-deploying-api-routes">Deploying API Routes</h2>
<p>When you deploy your Next.js application, API routes are automatically deployed as serverless functions. Popular platforms like Vercel and Netlify support this out of the box.</p>
<hr />
<h2 id="heading-use-cases-for-api-routes">Use Cases for API Routes</h2>
<ul>
<li><p><strong>Form Submission</strong>: Handle user input securely.</p>
</li>
<li><p><strong>Data Fetching</strong>: Integrate with third-party APIs or databases.</p>
</li>
<li><p><strong>Authentication</strong>: Validate user credentials and manage sessions.</p>
</li>
<li><p><strong>Dynamic Content</strong>: Generate personalized or real-time responses.</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Creating API routes in Next.js is straightforward and powerful. They allow you to add backend functionality without the need for a separate server. By following the steps above, you can build flexible and scalable API endpoints directly within your Next.js app. Start exploring the possibilities and enhance your applications with serverless API routes!</p>
]]></content:encoded></item></channel></rss>