<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Devarshi Shimpi</title>
    <description>The latest articles on Forem by Devarshi Shimpi (@devarshishimpi).</description>
    <link>https://forem.com/devarshishimpi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F838856%2Fcfa52442-fee6-4fa6-96c3-78c089e5d2e7.jpg</url>
      <title>Forem: Devarshi Shimpi</title>
      <link>https://forem.com/devarshishimpi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/devarshishimpi"/>
    <language>en</language>
    <item>
      <title>Voice Search in Chrome Extensions Is Harder Than It Looks</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Mon, 16 Mar 2026 15:57:17 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/voice-search-in-chrome-extensions-is-harder-than-it-looks-1pc</link>
      <guid>https://forem.com/devarshishimpi/voice-search-in-chrome-extensions-is-harder-than-it-looks-1pc</guid>
      <description>&lt;p&gt;I thought this was just an hour of work. It wasn't. Here's everything that went wrong and what actually worked in the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting with the obvious choice
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;window.SpeechRecognition&lt;/code&gt; is built into Chrome. No API keys, no server, completely free. It felt like the perfect starting point for adding voice search to my extension.&lt;br&gt;
After a day of testing, I dropped it.&lt;br&gt;
The mic permission popup was all over the place. Sometimes it would show up randomly mid-session. Sometimes it would just stop listening with no error, no warning, nothing. Results were different depending on the machine and OS. For a new tab extension that's meant to feel polished, that just wasn't good enough.&lt;br&gt;
I switched to Deepgram's Nova-3 model. It's fast, accurate, and sends results back in real time over WebSocket, so you don't have to wait for a full sentence before seeing any output.&lt;br&gt;
But now I needed a server, which kicked off a whole chain of problems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fciwmrs2euzvxjb7hcvb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fciwmrs2euzvxjb7hcvb7.png" alt="old-flow-browser-rec" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why you can't call Deepgram directly from the extension
&lt;/h2&gt;

&lt;p&gt;Chrome extensions are easy to unpack and read. Any secret you put in the code is basically public. So keeping a Deepgram API key in the client was never going to work.&lt;br&gt;
I needed a server in the middle. My first thought was Railway. I've used it before and getting a Node server running there takes maybe five minutes. But I second guessed that pretty quickly. A server on Railway means it has to start up cold sometimes, it costs money every month, and the speed depends on where the server is located. Cloudflare Workers runs closer to the user since it runs at the edge, and the free plan is generous enough that a voice search API would run for free forever. Easy choice.&lt;br&gt;
The setup I had in mind: the extension sends raw audio to the Worker, the Worker passes it to Deepgram, and the text comes back the same way.&lt;/p&gt;

&lt;p&gt;Simple enough on paper. Actually building it was another story.&lt;/p&gt;
&lt;h3&gt;
  
  
  Hono looked like the right tool. It wasn't.
&lt;/h3&gt;

&lt;p&gt;I use Hono for pretty much everything on Cloudflare Workers. Clean, fast, easy routing. So I reached for it without thinking twice.&lt;br&gt;
Set up a &lt;code&gt;/transcribe&lt;/code&gt; route, handled the WebSocket upgrade, deployed it. The Worker just froze. No error from my code, just Cloudflare eventually killing the request with a 500 and a message saying the Worker "would never generate a response."&lt;br&gt;
Took me a while to figure out what was going on. Cloudflare needs a special &lt;code&gt;webSocket&lt;/code&gt; property on the &lt;code&gt;Response&lt;/code&gt; object to finish a WebSocket connection. That's how it knows which socket to hand back to the client.&lt;br&gt;
Hono wraps the built-in &lt;code&gt;Response&lt;/code&gt; to add its own features. Somewhere in that process, the &lt;code&gt;webSocket&lt;/code&gt; property gets lost. Cloudflare gets a response with no socket, doesn't know what to do, and kills the request.&lt;br&gt;
The fix was to skip Hono for this route and just write it raw:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/transcribe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocketPair&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;101 Switching Protocols. Finally.&lt;/p&gt;

&lt;h3&gt;
  
  
  The timing bug I should've seen coming
&lt;/h3&gt;

&lt;p&gt;Audio was flowing but the Worker kept logging &lt;code&gt;Deepgram not ready&lt;/code&gt;. Pretty obvious in hindsight.&lt;br&gt;
The moment the client gets a 101 back, it starts sending audio right away. But the Worker had only just started its own connection to Deepgram. That connection wasn't open yet. So audio was showing up before Deepgram was ready to take it.&lt;br&gt;
My first fix was to wait for the Deepgram connection to open before sending the 101 back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;deepgramSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onopen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This worked. But it quietly created a new problem I didn't notice until later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloudflare's 10ms CPU limit is real
&lt;/h3&gt;

&lt;p&gt;The free plan on Cloudflare Workers gives you 10ms of CPU time per request. Not total time, just active processing time. Waiting on a network call doesn't count, so in theory waiting for Deepgram to connect should be fine.&lt;br&gt;
In practice, keeping the request open through the whole connection process added enough overhead that CPU usage was sitting at 40 to 90ms. Cloudflare was going to start dropping requests.&lt;/p&gt;

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

&lt;p&gt;The fix was to stop waiting. Return the 101 right away, let Deepgram connect in the background, and just hold any audio that comes in too early:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;deepgramReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pendingChunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="nx"&gt;deepgramSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;deepgramReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;pendingChunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;deepgramSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;pendingChunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;deepgramReady&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pendingChunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;deepgramSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CPU usage dropped to around 2ms. Deepgram still connects, it just doesn't hold everything else up while it does.&lt;/p&gt;

&lt;h3&gt;
  
  
  AudioWorklet and Manifest V3 don't work together
&lt;/h3&gt;

&lt;p&gt;This was the most painful part of the whole thing.&lt;br&gt;
MV3 extensions only let you run scripts that are part of your own extension package. No inline scripts, no scripts from other websites, nothing generated at runtime. &lt;code&gt;AudioWorkletNode&lt;/code&gt; is the standard modern way to process audio in a background thread, and it needs you to load a separate file using &lt;code&gt;addModule(url)&lt;/code&gt;. You can already see where this is going.&lt;/p&gt;

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

&lt;p&gt;First try was using Vite's &lt;code&gt;?url&lt;/code&gt; import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;processorUrl&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./processor.js?url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Output: data:text/javascript;base64,...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Blocked. Makes sense, data URIs aren't allowed.&lt;br&gt;
Second try was putting the file in the &lt;code&gt;public/&lt;/code&gt; folder and loading it with &lt;code&gt;chrome.runtime.getURL&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;audio/pcm-processor.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioWorklet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This really should have worked. A &lt;code&gt;chrome-extension://&lt;/code&gt; URL is from your own extension, so the policy should allow it. I was pretty sure this was the answer.&lt;br&gt;
It failed with &lt;code&gt;AbortError: Unable to load worklet module&lt;/code&gt;. No extra info, no useful error message.&lt;br&gt;
After going through Chromium bug reports, turns out this is a known broken behaviour in how Chrome handles extension files in Worklet threads. There are open issues, no fix in sight.&lt;/p&gt;
&lt;h3&gt;
  
  
  The old deprecated API that actually works
&lt;/h3&gt;

&lt;p&gt;I gave up on &lt;code&gt;AudioWorklet&lt;/code&gt; and used &lt;code&gt;ScriptProcessorNode&lt;/code&gt; instead. It's been marked as deprecated for years but it runs directly in the page using a callback, so there's no extra file to load and no policy issues. For converting Float32 audio to Int16, the performance hit is basically nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;audioCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createScriptProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onaudioprocess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inputBuffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getChannelData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;int16&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float32ToInt16&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;int16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Works every time without fail. The modern recommended way broke. The old way just works. That's extension development.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few smaller things worth knowing
&lt;/h2&gt;

&lt;p&gt;Cleaning up properly is harder than it sounds. Web Audio can leak memory if you don't clean up after yourself. When voice search stops, you need to close the WebSocket, disconnect the &lt;code&gt;ScriptProcessor&lt;/code&gt;, stop all microphone tracks (this turns off the mic light in the browser toolbar), and close the &lt;code&gt;AudioContext&lt;/code&gt;. Skip any one of these and you'll have audio processes running in the background that you can't see.&lt;br&gt;
Silence detection matters a lot. Without it, the mic just stays on forever. Every time Deepgram sends back a transcript or a &lt;code&gt;speech_started&lt;/code&gt; event, reset a 2.5 second timer. When the timer runs out, stop listening. It makes the whole thing feel much less annoying to use.&lt;br&gt;
Add the Worker URL to &lt;code&gt;host_permissions&lt;/code&gt; in your manifest. You need to allow &lt;code&gt;wss://your-worker.workers.dev/*&lt;/code&gt; or the browser blocks the connection before it even gets to any policy check.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually changed
&lt;/h2&gt;

&lt;p&gt;Before all of this, the extension was using &lt;code&gt;window.SpeechRecognition&lt;/code&gt; with around 500ms before it even started listening, results that changed between machines, and random failures. After the rewrite, it connects in around 100ms, the Worker uses 1 to 3ms of CPU per request, and it works the same way every time.&lt;br&gt;
Every single problem in this build came from the same place: the standard tools weren't built for this environment. Hono breaks WebSockets on Cloudflare. &lt;code&gt;AudioWorklet&lt;/code&gt; breaks in MV3 extensions. Once you understand why something fails, the fix is usually obvious. The hard part is getting there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Happy Coding!!!
&lt;/h2&gt;

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/self-hosting-your-own-cloud-storage-on-aws-using-nextcloud" rel="noopener noreferrer"&gt;Self-Hosting Your Own Cloud Storage on AWS using NextCloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/creating-your-first-droplet-digitalocean-tutorials" rel="noopener noreferrer"&gt;Creating Your First Droplet - DigitalOcean Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/complete-markdown-tutorial-for-beginners" rel="noopener noreferrer"&gt;Complete Markdown Tutorial for Beginners&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>React (RSC) Exploits Are Real and It's Hurting Engineering Teams</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Thu, 08 Jan 2026 16:11:01 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/react-rsc-exploits-are-real-and-its-hurting-engineering-teams-32mi</link>
      <guid>https://forem.com/devarshishimpi/react-rsc-exploits-are-real-and-its-hurting-engineering-teams-32mi</guid>
      <description>&lt;p&gt;If you work in web engineering, the transition into 2026 hasn’t been defined by new features, but by a single, terrifying realization: &lt;strong&gt;The boundary between your client and server is broken.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In December, "React2Shell" (&lt;a href="https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components" rel="noopener noreferrer"&gt;CVE-2025-55182&lt;/a&gt;) exposed a critical RCE in React Server Components. Barely after teams patched, two more high-severity exploits emerged in the same subsystem. This is the definitive technical post-mortem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "React2Shell" RCE (CVE-2025-55182)
&lt;/h2&gt;

&lt;p&gt;To understand why this vulnerability (CVSS 10.0) was so devastating, we first have to understand the machinery it destroyed, the &lt;strong&gt;React Flight Protocol&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For years, the mental model for React developers was simple: React renders UI in the browser, and an API (REST/GraphQL) fetches data. The server and client were distinct worlds, separated by a clear network boundary.&lt;/p&gt;

&lt;p&gt;React Server Components (RSC) erased that boundary.&lt;/p&gt;

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

&lt;p&gt;In the RSC world, the server doesn't send HTML to the client. It streams a proprietary serialization format called "Flight." This stream contains descriptions of UI components, serialized data, and crucially &lt;strong&gt;Promises&lt;/strong&gt; that resolve to data.&lt;/p&gt;

&lt;h3&gt;
  
  
  How React2Shell Works
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components" rel="noopener noreferrer"&gt;React2Shell&lt;/a&gt; was not standard SQL injection or XSS. It was logic abuse targeting a deserializer. Attackers crafted HTTP POST requests with specific "Flight" payloads. These binary-like streams mimicked valid component trees while hiding a "Thenable" Object, or fake Promise.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Injection:&lt;/strong&gt; Attacker sends serialized object containing malicious &lt;code&gt;__proto__&lt;/code&gt; keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deserialization:&lt;/strong&gt; Server parses stream and tries resolving fake Promise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prototype Pollution:&lt;/strong&gt; Lack of sanitization lets &lt;code&gt;__proto__&lt;/code&gt; overwrite &lt;code&gt;Object.prototype&lt;/code&gt; on running Node.js process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gadget Chain:&lt;/strong&gt; Modified prototype triggers internal calls targeting &lt;code&gt;Function&lt;/code&gt; constructor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Accessing &lt;code&gt;Function&lt;/code&gt; constructor means game over. Arbitrary strings like &lt;code&gt;require('child_process').exec(...)&lt;/code&gt; compile and execute immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Next.js was Affected
&lt;/h3&gt;

&lt;p&gt;Because &lt;a href="https://nextjs.org/blog/CVE-2025-66478" rel="noopener noreferrer"&gt;Next.js App Router&lt;/a&gt; enables RSC by default, &lt;strong&gt;every&lt;/strong&gt; Next.js application (versions 15.x, 16.x, and canary builds) was vulnerable out of the box. You didn't need to write a buggy Server Action to be hacked. You didn't even need to use Server Components explicitly. If your application booted up &lt;code&gt;react-server-dom-webpack&lt;/code&gt;, it was listening for these Flight payloads.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;Credits: Next.js for the image&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The DevOps Nightmare
&lt;/h3&gt;

&lt;p&gt;For DevOps engineers, "React2Shell" was a worst-case scenario.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WAF Blindness:&lt;/strong&gt; Standard Web Application Firewalls (WAFs) are trained to look for SQL injection (&lt;code&gt;' OR 1=1&lt;/code&gt;) or script tags (&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;). They were &lt;em&gt;not&lt;/em&gt; trained to inspect the proprietary text format of React Flight. The malicious payloads passed right through Cloudflare and AWS WAF rules initially.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supply Chain Hell:&lt;/strong&gt; The vulnerability wasn't in user code; it was deep in &lt;code&gt;node_modules&lt;/code&gt;. You couldn't just "fix the code." You had to wait for Vercel and the React team to release patched binaries, then rebuild and redeploy every single microservice.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Aftershocks (DoS and Leaks)
&lt;/h2&gt;

&lt;p&gt;Just as engineering teams were recovering from the RCE panic, the security community found more cracks in the foundation. On December 11, 2025, the &lt;a href="https://react.dev/blog/2025/12/11/denial-of-service-and-source-code-exposure-in-react-server-components" rel="noopener noreferrer"&gt;React team issued a new advisory&lt;/a&gt; for &lt;strong&gt;three&lt;/strong&gt; additional CVEs.&lt;/p&gt;

&lt;p&gt;While these aren't RCEs, they are operationally devastating and highlight the fragility of the current serialization implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Denial of Service (CVE-2025-55184)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Severity: High (7.5/10)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This vulnerability allows attackers to "freeze" infrastructure with a single request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mechanism:&lt;/strong&gt;&lt;br&gt;
Flight protocol allows data chunks to reference other chunks. Researchers discovered they could create &lt;strong&gt;circular dependencies&lt;/strong&gt; in payloads.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chunk A references Chunk B.&lt;/li&gt;
&lt;li&gt;Chunk B references Chunk A.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the React deserializer attempts to resolve this structure, it enters an &lt;strong&gt;infinite synchronous loop&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;The Impact on Infrastructure:&lt;/strong&gt;&lt;br&gt;
Because Node.js is single-threaded, this infinite loop blocks the entire Event Loop.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;CPU Spike:&lt;/strong&gt; The CPU immediately jumps to 100%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request Drops:&lt;/strong&gt; The server stops responding to &lt;em&gt;all&lt;/em&gt; other users. Health checks fail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluster Destabilization:&lt;/strong&gt; In Kubernetes, the liveness probe might fail, causing the pod to restart. But if the attacker sends a stream of these requests, they can put the entire cluster into a "CrashLoopBackOff" state, effectively taking down the application.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Note: The initial fix for this was incomplete, leading to CVE-2025-67779 (the "fix for the fix"), which forced DevOps teams to patch their systems a third time in two weeks.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Source Code Leak (CVE-2025-55183)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Severity: Medium (5.3/10)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Arguably most embarrassing vulnerability for React ecosystem. It allows attackers to trick servers into sending source code back to clients.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mechanism:&lt;/strong&gt;&lt;br&gt;
Exploit relies on JavaScript string coercion. If Server Action returns object implicitly calling &lt;code&gt;.toString()&lt;/code&gt; on a function within server runtime, default V8 behavior returns function &lt;strong&gt;source code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Secrets" Risk:&lt;/strong&gt;&lt;br&gt;
Developers often assume code inside &lt;code&gt;use server&lt;/code&gt; files is private. They might write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DO NOT DO THIS&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STRIPE_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sk_live_12345&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;purchase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Under normal circumstances, &lt;code&gt;STRIPE_KEY&lt;/code&gt; stays on the server. But with CVE-2025-55183, an attacker can manipulate the serialization of the return value to dump the scope of the function, potentially revealing hardcoded API keys, internal comments, and database schema details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Immediate Action Plan
&lt;/h3&gt;

&lt;p&gt;If you are running &lt;strong&gt;Next.js App Router (v13.3+)&lt;/strong&gt; or &lt;strong&gt;React 19&lt;/strong&gt;, you must execute the following plan immediately:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The "Immediate" Update:&lt;/strong&gt;
Do not trust semantic versioning ranges. Pin your versions to the releases that explicitly fix &lt;em&gt;all&lt;/em&gt; discussed CVEs.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react@19.0.2 react-dom@19.0.2 next@15.1.3
&lt;span class="c"&gt;# Verify deeply nested dependencies&lt;/span&gt;
npm list react-server-dom-webpack

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Ensure &lt;code&gt;react-server-dom-webpack&lt;/code&gt; is at least version 19.0.2.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implement Rate Limiting:&lt;/strong&gt;&lt;br&gt;
The DoS exploit is cheap for attackers. You must implement aggressive rate limiting on all routes, especially &lt;code&gt;POST&lt;/code&gt; requests, at the infrastructure level (Nginx, Cloudflare, AWS WAF).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Audit for Secrets:&lt;/strong&gt;&lt;br&gt;
Assume your server code &lt;em&gt;can&lt;/em&gt; be leaked. Run a scan of your &lt;code&gt;app/&lt;/code&gt; directory. If you find a single API key, hardcoded password, or internal IP address in a &lt;code&gt;.ts&lt;/code&gt; or &lt;code&gt;.js&lt;/code&gt; file, move it to an environment variable immediately.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;React Server Components are a powerful evolution of the web, but "React2Shell" has proven that this power comes with a terrifying new attack surface. The Flight protocol is complex, and as we have seen, complexity is the enemy of security.&lt;/p&gt;

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/managing-dependencies-and-security-with-npm" rel="noopener noreferrer"&gt;Managing Dependencies and Security in JavaScript with NPM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/google-ends-its-url-shortener-and-breaks-urls" rel="noopener noreferrer"&gt;The End of Google URL Shortener and breaks 4.6 BILLION URLs!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/managing-metadata-in-nextjs-for-seo" rel="noopener noreferrer"&gt;Managing Metadata in Next.js for Enhanced SEO and User Experience&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>nextjs</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Dynamic Styling with calc() in TailwindCSS</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Tue, 14 Oct 2025 22:01:56 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/dynamic-styling-with-calc-in-tailwindcss-5pp</link>
      <guid>https://forem.com/devarshishimpi/dynamic-styling-with-calc-in-tailwindcss-5pp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;TailwindCSS is fantastic, right? It lets us build beautiful, custom designs incredibly fast with its utility-first approach. We grab classes like &lt;code&gt;p-4&lt;/code&gt;, &lt;code&gt;flex&lt;/code&gt;, &lt;code&gt;w-1/2&lt;/code&gt;, and &lt;em&gt;boom&lt;/em&gt; – things start taking shape. But sometimes... sometimes you hit a wall. You need a layout element to be &lt;em&gt;exactly&lt;/em&gt; 100% wide, &lt;em&gt;minus&lt;/em&gt; the fixed width of a sidebar. Or maybe you want padding that dynamically adjusts based on the viewport &lt;em&gt;plus&lt;/em&gt; a base value.&lt;/p&gt;

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

&lt;p&gt;In this deep dive, we'll explore how &lt;code&gt;calc()&lt;/code&gt; works, why it's such a powerful partner for Tailwind, and how you can leverage it to build more sophisticated, responsive, and pixel-perfect interfaces without ever leaving your HTML (mostly!).&lt;/p&gt;

&lt;h2&gt;
  
  
  First Things First: What Exactly &lt;em&gt;is&lt;/em&gt; &lt;code&gt;calc()&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Before we plug it into Tailwind, let's quickly refresh ourselves on what &lt;code&gt;calc()&lt;/code&gt; actually does in plain old CSS. At its core, &lt;code&gt;calc()&lt;/code&gt; is a native CSS function that lets you perform calculations right inside your property values. Think of it like a mini-calculator for your stylesheets.&lt;/p&gt;

&lt;p&gt;It supports the basic arithmetic operations you'd expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Addition (&lt;code&gt;+&lt;/code&gt;)&lt;/strong&gt;: &lt;code&gt;calc(2rem + 10px)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subtraction (&lt;code&gt;-&lt;/code&gt;)&lt;/strong&gt;: &lt;code&gt;calc(100% - 50px)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiplication (&lt;code&gt;*&lt;/code&gt;)&lt;/strong&gt;: &lt;code&gt;calc(1.5 * 1rem)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Division (&lt;code&gt;/&lt;/code&gt;)&lt;/strong&gt;: &lt;code&gt;calc(100vw / 3)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This ability to blend relative and absolute units is something static values just can't replicate easily.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Full width minus a fixed sidebar */&lt;/span&gt;
&lt;span class="nc"&gt;.main-content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100%&lt;/span&gt; &lt;span class="n"&gt;-&lt;/span&gt; &lt;span class="m"&gt;250px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Dynamic padding based on viewport height */&lt;/span&gt;
&lt;span class="nc"&gt;.hero-section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5vh&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Bring &lt;code&gt;calc()&lt;/code&gt; into the Tailwind World?
&lt;/h2&gt;

&lt;p&gt;"Okay," you might be thinking, "Tailwind has spacing, sizing, fractions... why complicate things?"&lt;/p&gt;

&lt;p&gt;That's a fair question! Tailwind covers a &lt;em&gt;huge&lt;/em&gt; range of common styling needs with its utilities. But &lt;code&gt;calc()&lt;/code&gt; fills the gaps where:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;You Need Mixed Units:&lt;/strong&gt; Tailwind's &lt;code&gt;w-1/2&lt;/code&gt; is 50%, &lt;code&gt;w-64&lt;/code&gt; is 16rem. But what about &lt;code&gt;calc(50% - 1rem)&lt;/code&gt;? Tailwind doesn't have a pre-built utility for every possible mathematical combination.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;You Need Precise Dynamic Relationships:&lt;/strong&gt; Calculating an element's size based on the viewport &lt;em&gt;minus&lt;/em&gt; a fixed header/footer height is a prime use case.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;You Want Fluidity Beyond Standard Fractions:&lt;/strong&gt; Maybe a three-column layout needs precise gutters subtracted from fractional widths.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;You're Dealing with External Constraints:&lt;/strong&gt; Sometimes, an element's size needs to account for something outside its direct parent (like the viewport height).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Using Arbitrary Values &lt;code&gt;[]&lt;/code&gt; with &lt;code&gt;calc()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The framework embraced the idea that sometimes, you just need to write a specific CSS value directly. This is done using square brackets &lt;code&gt;[]&lt;/code&gt;. And guess what? You can put a &lt;code&gt;calc()&lt;/code&gt; expression right inside!&lt;/p&gt;

&lt;p&gt;The syntax looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"property-[calc(expression)]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see it in action:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a width that's full-width minus some padding:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-[calc(100%-2rem)] bg-blue-100 p-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  My width adapts, always leaving 1rem of space on each side (total 2rem).
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Setting a height relative to the viewport minus a header:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-16 bg-gray-800 text-white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-[calc(100vh-4rem)] bg-gray-100 overflow-y-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  This content area fills the remaining vertical space perfectly.
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Applying dynamic margins or padding:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-[calc(2rem+5vh)] bg-green-100 p-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  My top margin grows slightly as the viewport height increases.
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's that straightforward! You use the Tailwind property prefix (&lt;code&gt;w-&lt;/code&gt;, &lt;code&gt;h-&lt;/code&gt;, &lt;code&gt;mt-&lt;/code&gt;, &lt;code&gt;p-&lt;/code&gt;, etc.) followed by your &lt;code&gt;calc()&lt;/code&gt; expression wrapped in square brackets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Get Practical: Real-World &lt;code&gt;calc()&lt;/code&gt; Scenarios in Tailwind
&lt;/h2&gt;

&lt;p&gt;Theory is nice, but let's see where &lt;code&gt;calc()&lt;/code&gt; truly shines in everyday development with Tailwind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 1: The Classic Sidebar + Content Layout
&lt;/h3&gt;

&lt;p&gt;This is a bread-and-butter layout. You have a fixed-width sidebar and want the main content area to take up the &lt;em&gt;rest&lt;/em&gt; of the available space.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex min-h-screen"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;aside&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-64 bg-gray-100 p-4 flex-shrink-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Sidebar Content
  &lt;span class="nt"&gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-[calc(100%-16rem)] bg-white p-6 flex-grow"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Main Application Content Here...
    It perfectly fills the space next to the sidebar.
  &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;w-[calc(100%-16rem)]&lt;/code&gt; explicitly tells the main content area to calculate its width based on the full container width minus the sidebar's known width. &lt;code&gt;flex-shrink-0&lt;/code&gt; on the sidebar prevents it from shrinking if space gets tight, and &lt;code&gt;flex-grow&lt;/code&gt; on main allows it to expand (though the &lt;code&gt;calc()&lt;/code&gt; width often makes this redundant, it's good practice in flex layouts).&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Example 2: Making Room for Fixed Headers/Footers
&lt;/h3&gt;

&lt;p&gt;Sticky headers are common, but they can overlap content or require awkward padding. &lt;code&gt;calc()&lt;/code&gt; makes managing the space elegant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col min-h-screen"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-16 bg-indigo-600 text-white p-4 sticky top-0 z-10"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Fixed Header
  &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-grow p-6 bg-gray-50"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"padding-top: calc(4rem + 1.5rem);"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Content Section
  &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-[calc(100vh-4rem)] bg-gray-100 p-6 overflow-y-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
     This section takes exactly the remaining viewport height below the header.
  &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;footer&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-12 bg-gray-700 text-white p-3 mt-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Footer
  &lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;section&lt;/code&gt; example, &lt;code&gt;h-[calc(100vh-4rem)]&lt;/code&gt; ensures that specific part of the page uses precisely the vertical space available below the 4rem header. No guesswork needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 3: Fluid Typography That Breathes
&lt;/h3&gt;

&lt;p&gt;Want your text headings to scale smoothly with the viewport width, not just jump between breakpoints? &lt;code&gt;calc()&lt;/code&gt; combined with viewport units (&lt;code&gt;vw&lt;/code&gt;) is your friend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-[calc(1.5rem+2vw)] font-bold text-gray-900 leading-tight"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  This Headline Scales Fluidly
&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-[calc(1rem+0.5vw)] text-gray-700"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Even paragraph text can subtly adapt to the screen size, improving readability across devices.
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the font size has a base value (&lt;code&gt;1.5rem&lt;/code&gt; or &lt;code&gt;1rem&lt;/code&gt;) and adds a small percentage of the viewport width (&lt;code&gt;2vw&lt;/code&gt; or &lt;code&gt;0.5vw&lt;/code&gt;). This creates a much smoother scaling effect than relying solely on &lt;code&gt;text-lg&lt;/code&gt;, &lt;code&gt;text-xl&lt;/code&gt;, etc., at different breakpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 4: Precise Centering and Positioning
&lt;/h3&gt;

&lt;p&gt;Sometimes &lt;code&gt;flex&lt;/code&gt; or &lt;code&gt;grid&lt;/code&gt; centering isn't quite right, especially for absolutely positioned elements or overlays where you need an offset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"relative h-screen bg-gray-200"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"absolute top-[calc(50%-50px)] left-[50%] -translate-x-1/2 -translate-y-1/2 bg-white p-8 rounded shadow-lg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    I'm centered horizontally, but slightly offset vertically!
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;top-[calc(50%-50px)]&lt;/code&gt; positions the element's top edge 50 pixels &lt;em&gt;above&lt;/em&gt; the halfway point of the container, while the &lt;code&gt;transform&lt;/code&gt; utilities handle the rest of the centering adjustment based on the element's own size.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Going Beyond Arbitrary Values: Custom &lt;code&gt;calc()&lt;/code&gt; Utilities
&lt;/h2&gt;

&lt;p&gt;Arbitrary values are fantastic for one-offs. But what if you find yourself repeatedly using the same &lt;code&gt;calc()&lt;/code&gt; expression? Like that &lt;code&gt;h-[calc(100vh-4rem)]&lt;/code&gt; for content below your standard header? Typing that out every time is tedious and error-prone.&lt;/p&gt;

&lt;p&gt;This is where extending your Tailwind configuration shines. You can define your own custom utilities that encapsulate these common calculations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add this to your &lt;code&gt;tailwind.config.ts&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Example: Add custom height calculation&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;screen-minus-header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;calc(100vh - 4rem)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Assuming 4rem header&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;// Example: Add custom width calculation&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-area&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;calc(100% - 16rem)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Assuming 16rem sidebar&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;// Example: Add custom spacing&lt;/span&gt;
      &lt;span class="na"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dynamic-gutter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;calc(1rem + 2vw)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// Ensure your content paths are configured here&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/**/*.{html,js,jsx,ts,tsx,vue}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can use these just like native Tailwind utilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-screen-minus-header w-content-area p-dynamic-gutter"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Look Ma, custom calc utilities!
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes your HTML cleaner, your calculations consistent, and your design system more robust.&lt;/p&gt;

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

&lt;p&gt;TailwindCSS provides an incredible foundation for rapid UI development. By understanding and integrating the native CSS &lt;code&gt;calc()&lt;/code&gt; function through arbitrary values and custom configurations, you unlock a whole new level of dynamic control and precision.&lt;/p&gt;

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/creating-your-first-droplet-digitalocean-tutorials" rel="noopener noreferrer"&gt;Creating Your First Droplet - DigitalOcean Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/top-ten-vscode-extensions-you-need-in-twentytwentytwo" rel="noopener noreferrer"&gt;Top 10 VS CODE Extensions You Need In 2022!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/setting-up-an-ubuntu-ec2-instance-from-scratch-on-aws" rel="noopener noreferrer"&gt;Setting Up An Ubuntu EC2 Instance From Scratch on AWS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>tailwindcss</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Introduction to Next.js 15: What's New and the improvements!</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Tue, 17 Dec 2024 05:30:00 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/introduction-to-nextjs-15-whats-new-and-the-improvements-1eob</link>
      <guid>https://forem.com/devarshishimpi/introduction-to-nextjs-15-whats-new-and-the-improvements-1eob</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Next.js 15 has introduced a range of exciting features and improvements that enhance both performance and developer experience. Here’s a detailed overview of what's new!&lt;/p&gt;

&lt;h2&gt;
  
  
  Seamless Upgrades with &lt;a class="mentioned-user" href="https://dev.to/next"&gt;@next&lt;/a&gt;/codemod CLI
&lt;/h2&gt;

&lt;p&gt;The enhanced codemod CLI simplifies upgrading to the latest Next.js and React versions. It automates code transformations, ensuring a smooth transition to new APIs and features.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @next/codemod@canary upgrade latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Performance Enhancements
&lt;/h3&gt;

&lt;p&gt;Next.js 15 focuses heavily on improving the speed and efficiency of applications:&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Turbopack Boost:&lt;/strong&gt; Next.js 15's integration with Turbopack accelerates development server startup by up to 53%, providing faster feedback loops.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hybrid Rendering:&lt;/strong&gt; Partial prerendering combines static and dynamic content for quicker initial loads and improved user experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enhanced Caching:&lt;/strong&gt; Optimized caching strategies reduce network requests, resulting in faster load times and predictable data fetching.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Developer Experience (DX) Improvements
&lt;/h3&gt;

&lt;p&gt;Next.js 15 prioritizes the developer experience with several new tools and features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous Request-Specific APIs&lt;/strong&gt;: APIs for handling cookies, headers, and search parameters have been updated to support asynchronous operations. This change allows for cleaner code and enhances application responsiveness.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;New Debugging Tools&lt;/strong&gt;: Enhanced error messages and stack traces make debugging more efficient, helping developers quickly identify and resolve issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;New Form Component&lt;/strong&gt;: A built-in form component simplifies form handling by eliminating the need for third-party libraries. It supports automatic validation, and progressive enhancement, ensuring that forms work even without JavaScript enabled.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"query"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Experimental Authorization APIs&lt;/strong&gt;: New APIs for handling authorization errors (&lt;code&gt;forbidden&lt;/code&gt; and &lt;code&gt;unauthorized&lt;/code&gt;) provide granular control over authentication processes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TypeScript Configuration Support&lt;/strong&gt;: Developers can now use TypeScript for their configuration files by renaming &lt;code&gt;next.config.js&lt;/code&gt; to &lt;code&gt;next.config.ts&lt;/code&gt;. This feature improves type safety and autocompletion, reducing errors during development.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* config options here */&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Static Route Indicator
&lt;/h3&gt;

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

&lt;p&gt;Next.js now displays a Static Route Indicator during development to help you identify which routes are static or dynamic. This visual cue makes it easier to optimize performance by understanding how your pages are rendered.&lt;/p&gt;

&lt;h3&gt;
  
  
  New Middleware Capabilities
&lt;/h3&gt;

&lt;p&gt;A standout feature in Next.js 15 is the introduction of middleware, which allows developers to run code before requests are completed. This is particularly useful for tasks such as authentication and logging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Support for React 19 and ESLint 9
&lt;/h3&gt;

&lt;p&gt;Next.js 15 officially supports React 19, which introduces several performance optimizations and new features including the new &lt;strong&gt;React Compiler&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It also adds support for ESLint 9 while maintaining backward compatibility with ESLint 8. This ensures better code quality through improved linting capabilities tailored for React hooks usage.&lt;/p&gt;

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

&lt;p&gt;Next.js 15 represents a significant advancement in web development capabilities with its blend of performance enhancements, improved developer tools, and robust support for modern React features.&lt;/p&gt;

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/what-are-docker-images-and-how-to-use-them" rel="noopener noreferrer"&gt;What Are Docker Images And How To Use Them&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/creating-your-first-droplet-digitalocean-tutorials" rel="noopener noreferrer"&gt;Creating Your First Droplet - DigitalOcean Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/setting-up-an-ubuntu-ec2-instance-from-scratch-on-aws" rel="noopener noreferrer"&gt;Setting Up An Ubuntu EC2 Instance From Scratch on AWS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Managing Dependencies and Security in JavaScript with NPM</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Fri, 09 Aug 2024 13:13:19 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/managing-dependencies-and-security-in-javascript-with-npm-2k6m</link>
      <guid>https://forem.com/devarshishimpi/managing-dependencies-and-security-in-javascript-with-npm-2k6m</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The JavaScript ecosystem, particularly with &lt;strong&gt;NPM&lt;/strong&gt;, &lt;em&gt;is both a boon and a bane for developers&lt;/em&gt;. On one hand, it provides an incredibly vast library of modules that can accelerate development. On the other hand, it can feel like a tangled web of dependencies, raising legitimate security concerns. Let's dive deep into the intricacies of NPM, the security implications, and how modern bundlers mitigate these risks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding NPM and Its Ecosystem
&lt;/h2&gt;

&lt;p&gt;NPM is the default package manager for Node.js, which is widely used for server-side and full-stack JavaScript development. It allows developers to easily install, share, and manage code modules.&lt;/p&gt;

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

&lt;p&gt;The convenience it offers has made it a cornerstone of modern JavaScript development. However, with great convenience comes great responsibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Dependency Hell
&lt;/h3&gt;

&lt;p&gt;When you set up a basic project with &lt;strong&gt;NPM&lt;/strong&gt;, you often find yourself pulling in numerous dependencies. Each dependency can have its own dependencies, creating a cascading effect that can quickly spiral out of control. This phenomenon is often referred to as &lt;strong&gt;dependency hell&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consider this scenario:&lt;/strong&gt; You install a popular library like &lt;a href="https://www.npmjs.com/package/tailwindcss" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt;. TailwindCSS itself has a few dependencies.&lt;/p&gt;

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

&lt;p&gt;Those dependencies, in turn, have their own dependencies, and so on. Before you know it, your project has hundreds of packages installed, many of which you may not be familiar with. This can make your project more vulnerable to security risks, as it’s challenging to vet each package and its updates.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The Security Concerns
&lt;/h2&gt;

&lt;p&gt;One of the primary security concerns with NPM is the potential for malicious code to be introduced into your project through dependencies. This can happen in a few ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compromised Packages&lt;/strong&gt;: A legitimate package you depend on might get compromised. This can happen if a maintainer's account is hacked or if the maintainer themselves goes rogue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Typosquatting&lt;/strong&gt;: Malicious actors sometimes publish packages with names similar to popular packages, hoping that developers will mistype the name and inadvertently install the malicious package.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dependency Chains&lt;/strong&gt;: Even if your direct dependencies are secure, they might depend on other packages that are not. This creates a long chain of trust that can be difficult to manage.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Polyfill.io Incident
&lt;/h3&gt;

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

&lt;p&gt;Link to the article &lt;a href="https://arcticwolf.com/resources/blog/polyfill-supply-chain-attack-impacts-100k-sites/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A recent incident involving a service called Polyfill.io highlighted these risks. &lt;strong&gt;Polyfill.io&lt;/strong&gt; is a &lt;strong&gt;CDN service&lt;/strong&gt; that provides &lt;em&gt;JavaScript polyfills for older browsers&lt;/em&gt;. It was discovered that this service could potentially serve different versions of the same script based on the browser's user agent. This variability made it impossible to use integrity checks to verify the script, creating a security vulnerability.&lt;/p&gt;

&lt;p&gt;Many websites, including high-profile ones like Hulu, were loading scripts from this service. This incident underscores the dangers of relying on third-party CDNs for critical scripts, as a compromise in the CDN can lead to widespread vulnerabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, Are We Trading Security for Convenience?
&lt;/h3&gt;

&lt;p&gt;Yes, managing dependencies in a large software project is inherently complex, and no system is foolproof. However, modern package managers, bundlers, and security best practices provide robust safeguards against most common attack vectors.&lt;/p&gt;

&lt;p&gt;The key takeaway is this: understand how your tools work. Don't blindly trust; verify. Pin your dependency versions, audit your dependencies regularly, and stay informed about potential vulnerabilities. By adopting a proactive security mindset and leveraging the tools at your disposal, you can reap the benefits of a vibrant package ecosystem without compromising the integrity of your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modern Bundlers to the Rescue
&lt;/h2&gt;

&lt;p&gt;Fortunately, modern JavaScript development has tools to mitigate these risks. Bundlers like Webpack, Vite, and Rollup play a crucial role in ensuring the security and efficiency of web applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Bundler?
&lt;/h3&gt;

&lt;p&gt;A bundler takes the various modules and dependencies in your project and combines them into a single file (or a few files) that can be efficiently loaded by the browser. This process not only improves performance by reducing the &lt;em&gt;number of HTTP requests&lt;/em&gt; but also helps in managing dependencies more securely.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Bundlers Improve Security
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local Assets&lt;/strong&gt;: When you build your project using a bundler, it compiles all your code and dependencies into a single bundle. This means that your application is &lt;strong&gt;serving all its JavaScript&lt;/strong&gt; from &lt;strong&gt;your own domain&lt;/strong&gt;, &lt;strong&gt;not relying on third-party CDNs&lt;/strong&gt;. This significantly reduces the risk of third-party script compromises.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lock Files&lt;/strong&gt;: NPM generates a &lt;code&gt;package-lock.json&lt;/code&gt; file that locks the versions of all installed packages. This ensures that the same versions are used every time someone installs your project, even if newer versions of the dependencies are released. This consistency is crucial for security.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Integrity Checks&lt;/strong&gt;: Modern build tools can include integrity checks to ensure that the files served to the browser match the expected hashes. This makes it harder for compromised or altered packages to go unnoticed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example with Vite
&lt;/h3&gt;

&lt;p&gt;Let's take Vite, a modern bundler, as an example. When you install dependencies and build your project with Vite, it bundles all the necessary JavaScript files into a single minified file. Here’s a step-by-step of what happens:&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install Dependencies&lt;/strong&gt;: You install your dependencies using NPM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build the Project&lt;/strong&gt;: You run &lt;code&gt;vite build&lt;/code&gt;, which compiles your project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Serve Local Assets&lt;/strong&gt;: When you deploy your project, all the JavaScript files are served from your own domain. No external CDNs are involved.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process ensures that the JavaScript running on your site is exactly what you expect, with no surprises from third-party CDNs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Addressing Common Misconceptions
&lt;/h2&gt;

&lt;p&gt;There are several misconceptions about NPM and modern JavaScript development that contribute to the fear of security risks. Let’s address some of these:&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconception 1: NPM Directly Serves Files to Users
&lt;/h3&gt;

&lt;p&gt;Some believe that when users visit a site, they are directly fetching files from NPM. This is not true. NPM is used to manage and install dependencies during the development process. When you build and deploy your project, all the code is served from your own servers, not from NPM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconception 2: Dev Dependencies are Included in Production
&lt;/h3&gt;

&lt;p&gt;Another common misconception is that dev dependencies (packages used for development purposes, like testing or linting tools) are included in the final bundle served to users. This is false. Dev dependencies are only used during development and are not included in the production build.&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconception 3: Package Lock Files are Unnecessary
&lt;/h3&gt;

&lt;p&gt;Some developers overlook the importance of &lt;code&gt;package-lock.json&lt;/code&gt; files. These files ensure that the exact same versions of dependencies are used every time the project is installed, which is crucial for maintaining security and consistency. Without a lock file, there’s a risk of pulling in newer, potentially compromised versions of dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for Secure JavaScript Development
&lt;/h2&gt;

&lt;p&gt;To further mitigate security risks, follow these best practices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Regular Audits&lt;/strong&gt;: Regularly audit your dependencies using tools like &lt;code&gt;npm audit&lt;/code&gt; to identify and address vulnerabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lock File Maintenance&lt;/strong&gt;: Always use and maintain your &lt;code&gt;package-lock.json&lt;/code&gt; file. Ensure that your CI/CD pipelines respect the lock file to prevent accidental upgrades.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dependency Management&lt;/strong&gt;: Be mindful of the dependencies you add to your project. Avoid unnecessary dependencies and consider the reputation and activity of the package maintainers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Trusted Sources&lt;/strong&gt;: Prefer well-established libraries and avoid packages with unclear or questionable histories.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stay Updated&lt;/strong&gt;: Keep your dependencies up to date with the latest security patches. Tools like Dependabot can automate this process for you.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By taking proactive steps to secure your dependencies and being aware of how your tools work, you can harness the power of NPM and modern JavaScript development while keeping your projects safe and secure.&lt;/p&gt;

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

&lt;p&gt;The NPM ecosystem, with its vast library of packages, undeniably brings convenience to JavaScript development. However, it also introduces potential security risks that cannot be ignored. Understanding how modern bundlers work, maintaining a strict dependency management strategy, and following best practices can significantly mitigate these risks.&lt;/p&gt;

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bio.link/devarshishimpi" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/how-to-create-a-new-nextjs-project-with-cf-workers-and-pages" rel="noopener noreferrer"&gt;How to create a new Next.js project with Cloudflare Pages and Workers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/easiest-way-to-install-wordpress-for-beginners" rel="noopener noreferrer"&gt;Easiest Way to Install WordPress Locally for Beginners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/wordpresscom-wordpressorg-the-differences-which-to-choose" rel="noopener noreferrer"&gt;WordPress.com vs. WordPress.org The Differences &amp;amp; Which To Choose&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The End of Google URL Shortener and breaks 4.6 BILLION URLs!</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Thu, 01 Aug 2024 11:18:20 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/the-end-of-google-url-shortener-and-breaks-46-billion-urls-4o1</link>
      <guid>https://forem.com/devarshishimpi/the-end-of-google-url-shortener-and-breaks-46-billion-urls-4o1</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The innovations Google has brought to the table, from Chrome to the Google ecosystem, have undeniably shaped the internet. But sometimes, their decisions leave us scratching our heads, frustrated and disappointed. One such decision is the end of &lt;code&gt;goo.gl&lt;/code&gt;, their URL shortener service, which brings back memories of other products they have shelved over the years—like Google Reader and, more recently, Google Domains.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rise and Fall of goo.gl
&lt;/h2&gt;

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

&lt;p&gt;When &lt;a href="https://goo.gl" rel="noopener noreferrer"&gt;goo.gl&lt;/a&gt; was launched, it was a nifty tool that made sharing long, cumbersome URLs a breeze. It offered analytics and QR codes, making it a favorite among both casual users and developers.&lt;/p&gt;

&lt;p&gt;But in 2018, Google announced that it would no longer support the creation of new goo.gl links, nudging users towards alternatives like &lt;a href="https://firebase.google.com/docs/dynamic-links" rel="noopener noreferrer"&gt;Firebase Dynamic Links&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fast forward to now, and we've learned that all goo.gl links will completely stop working by August 2025. This isn’t just about not being able to make new links anymore; it means that all existing links will die. Clicking on them after the cutoff date will lead to a 404 error -- a digital dead end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives to Google URL Shortener
&lt;/h2&gt;

&lt;p&gt;Google suggested &lt;a href="(https://firebase.google.com/docs/dynamic-links)"&gt;Firebase Dynamic Links&lt;/a&gt; as an alternative, but guess what? That service is also being deprecated on August 25, 2025. It's a frustrating loop, recommending one product as a replacement only to kill it off later. It makes planning and continuity a nightmare for users.&lt;/p&gt;

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

&lt;p&gt;As goo.gl sunsets, users are left seeking alternatives. Services like Bitly, TinyURL, and &lt;a href="https://dub.co" rel="noopener noreferrer"&gt;dub.co&lt;/a&gt; offer similar functionalities, each service comes with its own set of features, policies, and levels of reliability.&lt;/p&gt;

&lt;p&gt;I personally prefer &lt;a href="https://dub.co" rel="noopener noreferrer"&gt;dub.co&lt;/a&gt; and it has been great in my experience till now. Their team was quick enough to even make the migration process as seamless as possible! Especially their quick alternative as &lt;strong&gt;ggl.link&lt;/strong&gt;&lt;/p&gt;

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

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

&lt;p&gt;The decision to end goo.gl is a reminder of the impermanence of digital tools. While Google's decision might be based on practical considerations, the impact on users is real and far-reaching. It disrupts current operations, potentially erases valuable information, and once again highlights the precariousness of relying on a single company for critical digital infrastructure.&lt;/p&gt;

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bio.link/devarshishimpi" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/what-are-docker-images-and-how-to-use-them" rel="noopener noreferrer"&gt;What Are Docker Images And How To Use Them&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/creating-your-first-droplet-digitalocean-tutorials" rel="noopener noreferrer"&gt;Creating Your First Droplet - DigitalOcean Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/setting-up-an-ubuntu-ec2-instance-from-scratch-on-aws" rel="noopener noreferrer"&gt;Setting Up An Ubuntu EC2 Instance From Scratch on AWS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>news</category>
      <category>google</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to create a new Next.js project with Cloudflare Pages and Workers</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Thu, 18 Jul 2024 14:58:33 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/how-to-create-a-new-nextjs-project-with-cloudflare-pages-and-workers-43d9</link>
      <guid>https://forem.com/devarshishimpi/how-to-create-a-new-nextjs-project-with-cloudflare-pages-and-workers-43d9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this guide, we'll walk through creating a new Next.js 14 project using TypeScript and deploying it on Cloudflare Pages with Workers for a full-stack solution. We'll use the &lt;code&gt;create-cloudflare&lt;/code&gt; CLI (C3) to set up our project, and deploy the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create a new Git repository
&lt;/h3&gt;

&lt;p&gt;Go to &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, click the "+" icon in the top right, and select &lt;strong&gt;"New repository"&lt;/strong&gt;. Set the repository name to &lt;code&gt;nextjs-cf-pages-workers&lt;/code&gt; or whatever you would like to, choose Public or Private visibility, and click &lt;strong&gt;"Create repository"&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;Your new repository is now ready! Clone the repository and get ready for the next step!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create a New Next.js Project
&lt;/h3&gt;

&lt;p&gt;To get started, we'll use the &lt;code&gt;create-cloudflare&lt;/code&gt; CLI (C3) to create a new Next.js project. Open your terminal and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create cloudflare@latest my-next-app &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--framework&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command initializes a new Next.js project in a directory named &lt;code&gt;my-next-app&lt;/code&gt;. Follow the prompts to configure your project. The CLI will install the necessary dependencies, including the Wrangler CLI and the &lt;code&gt;@cloudflare/next-on-pages&lt;/code&gt; adapter.&lt;/p&gt;

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

&lt;p&gt;In your terminal, this is how it should look like. After the project is created, navigate to the project directory, and run &lt;code&gt;npm run dev&lt;/code&gt;. You should have a browser preview like this:&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Step 3: Configure the Project for Cloudflare Pages
&lt;/h3&gt;

&lt;p&gt;You can deploy using mutliple options, I have covered 2 in this article.&lt;/p&gt;

&lt;p&gt;Log in to the Cloudflare dashboard and select your account. Navigate to Workers &amp;amp; Pages &amp;gt; Create application &amp;gt; Pages &amp;gt; Connect to Git. Authorize access to your GitHub account and select the new repository you created.&lt;/p&gt;

&lt;p&gt;Make sure you have added &lt;code&gt;nodejs_compat&lt;/code&gt; as the compatibility flags or the build will fail!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Configure and Deploy Without C3
&lt;/h3&gt;

&lt;p&gt;If you prefer not to use C3, you can manually configure and deploy your project. Install the &lt;code&gt;@cloudflare/next-on-pages&lt;/code&gt; adapter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @cloudflare/next-on-pages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Set Up Bindings for Local Development
&lt;/h3&gt;

&lt;p&gt;Bindings allow your application to interact with Cloudflare developer products. To set up bindings for local development, modify your Next.js configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// next.config.mjs&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setupDevPlatform&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cloudflare/next-on-pages/next-dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setupDevPlatform&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** @type {import('next').NextConfig} */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure you have a &lt;code&gt;wrangler.toml&lt;/code&gt; file at the root of your project with a KV binding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# wrangler.toml&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-next-app"&lt;/span&gt;
&lt;span class="py"&gt;compatibility_flags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"nodejs_compat"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nn"&gt;[[kv_namespaces]]&lt;/span&gt;
&lt;span class="py"&gt;binding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"MY_KV"&lt;/span&gt;
&lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;YOUR_KV_NAMESPACE_ID&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can run the following command and it should deploy the project as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Success!
&lt;/h2&gt;

&lt;p&gt;By following these steps, you've successfully created and deployed a full-stack Next.js 14 project with TypeScript on Cloudflare Pages and Workers. This setup leverages Cloudflare's powerful developer products to enhance your application's capabilities.&lt;/p&gt;

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

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

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bio.link/devarshishimpi" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/what-are-docker-images-and-how-to-use-them" rel="noopener noreferrer"&gt;What Are Docker Images And How To Use Them&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/creating-your-first-droplet-digitalocean-tutorials" rel="noopener noreferrer"&gt;Creating Your First Droplet - DigitalOcean Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/setting-up-an-ubuntu-ec2-instance-from-scratch-on-aws" rel="noopener noreferrer"&gt;Setting Up An Ubuntu EC2 Instance From Scratch on AWS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>beginners</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Managing Metadata in Next.js for Enhanced SEO and User Experience</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Tue, 02 Jul 2024 11:13:43 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/managing-metadata-in-nextjs-14-for-enhanced-seo-and-user-experience-3aam</link>
      <guid>https://forem.com/devarshishimpi/managing-metadata-in-nextjs-14-for-enhanced-seo-and-user-experience-3aam</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In Next.js 14, there are two primary ways to manage metadata for your application: using a static &lt;code&gt;metadata&lt;/code&gt; object or a dynamic &lt;code&gt;generateMetadata&lt;/code&gt; function. Below is a detailed guide on how to utilize both options effectively.&lt;/p&gt;

&lt;p&gt;This guide provides an in-depth look at both approaches, helping you understand how to effectively implement metadata in your Next.js application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next.js Demo with Metadata Output
&lt;/h2&gt;

&lt;p&gt;In this live example, we'll create a simple Next.js application showcasing the usage of metadata.  Then, we'll view the rendered output in the browser and visualise the metadata in action.&lt;/p&gt;

&lt;p&gt;We start by creating a new Next.js project with &lt;code&gt;create-next-app&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the options I chose while creating it.&lt;/p&gt;

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

&lt;p&gt;Add this sample code in the following block and let's preview it in the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code:&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And here's the browser output with get with the tags, keep reading the entire article to see how you could implement in your code.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Static Metadata
&lt;/h3&gt;

&lt;p&gt;To define static metadata, you export a &lt;code&gt;Metadata&lt;/code&gt; object from a &lt;code&gt;layout.ts&lt;/code&gt; or &lt;code&gt;page.ts&lt;/code&gt; file using the App Router.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Static Page Title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This is a static page description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method is suitable when the metadata does not depend on runtime information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamic Metadata
&lt;/h3&gt;

&lt;p&gt;Dynamic metadata allows you to generate metadata based on dynamic data, such as route parameters or fetched data.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ResolvingMetadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nl"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ResolvingMetadata&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Metadata&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.example.com/products/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;previousImages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;previousImages&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method is useful when the metadata depends on dynamic data or needs to extend parent metadata.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Points
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server Components Only&lt;/strong&gt;: Both &lt;code&gt;metadata&lt;/code&gt; and &lt;code&gt;generateMetadata&lt;/code&gt; are only supported in Server Components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single Export Rule&lt;/strong&gt;: You cannot export both the &lt;code&gt;metadata&lt;/code&gt; object and &lt;code&gt;generateMetadata&lt;/code&gt; function from the same route segment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Metadata Fields
&lt;/h3&gt;

&lt;p&gt;Next.js provides a variety of metadata fields to customize the metadata of your application comprehensively.&lt;/p&gt;

&lt;h4&gt;
  
  
  Title
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;String&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Next.js Application&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output: &lt;code&gt;&amp;lt;title&amp;gt;Next.js Application&amp;lt;/title&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Template Object&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;%s | Next.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output in child routes: &lt;code&gt;&amp;lt;title&amp;gt;About | Next.js&amp;lt;/title&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Absolute&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;About Us&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output: &lt;code&gt;&amp;lt;title&amp;gt;About Us&amp;lt;/title&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Description
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The React Framework for the Web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output: &lt;code&gt;&amp;lt;meta name="description" content="The React Framework for the Web" /&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Basic Fields
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;applicationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Next.js App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;React&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JavaScript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;authors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Author Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"generator"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Next.js"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"application-name"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Next.js App"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"keywords"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Next.js,React,JavaScript"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"author"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Author Name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"author"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Open Graph
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The React Framework for the Web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://nextjs.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;siteName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://nextjs.org/og.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en_US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;website&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Next.js"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"The React Framework for the Web"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://nextjs.org/"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:site_name"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Next.js"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:locale"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"en_US"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://nextjs.org/og.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:width"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:height"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Twitter
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;summary_large_image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The React Framework for the Web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://nextjs.org/og.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Next.js"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"The React Framework for the Web"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://nextjs.org/og.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Robots
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;robots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;googleBot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"robots"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"noindex, follow"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"googlebot"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"index, nofollow"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  MetadataBase
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;metadataBase&lt;/code&gt; allows setting a base URL prefix for metadata fields that require a fully qualified URL.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;metadataBase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/og-image.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/og-image.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Best Practices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use Static Metadata When Possible&lt;/strong&gt;: If metadata doesn't depend on runtime information, prefer static metadata for simplicity.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dynamic Metadata for Dynamic Data&lt;/strong&gt;: Use &lt;code&gt;generateMetadata&lt;/code&gt; for routes where metadata depends on dynamic data or needs to extend parent metadata.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Combine Metadata Fields&lt;/strong&gt;: Utilize a combination of different metadata fields to ensure comprehensive metadata coverage for SEO and social media integration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Utilize &lt;code&gt;metadataBase&lt;/code&gt;&lt;/strong&gt;: Set a &lt;code&gt;metadataBase&lt;/code&gt; in your root layout to simplify URL-based metadata field definitions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;By following these guidelines, you can effectively manage metadata in your Next.js 14 application, enhancing both SEO and user experience.&lt;/p&gt;

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bio.link/devarshishimpi" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/what-are-docker-images-and-how-to-use-them" rel="noopener noreferrer"&gt;What Are Docker Images And How To Use Them&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/creating-your-first-droplet-digitalocean-tutorials" rel="noopener noreferrer"&gt;Creating Your First Droplet - DigitalOcean Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/setting-up-an-ubuntu-ec2-instance-from-scratch-on-aws" rel="noopener noreferrer"&gt;Setting Up An Ubuntu EC2 Instance From Scratch on AWS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Google's AI-Powered Cloud IDE Project IDX Goes Open Beta!</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Mon, 10 Jun 2024 09:39:50 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/googles-ai-powered-cloud-ide-project-idx-goes-open-beta-3lgl</link>
      <guid>https://forem.com/devarshishimpi/googles-ai-powered-cloud-ide-project-idx-goes-open-beta-3lgl</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;At the &lt;strong&gt;2024 Google I/O developer conference&lt;/strong&gt;, Google unveiled an exciting new tool for developers—Project IDX. Now in open beta, Project IDX is set to revolutionise the way we approach web and mobile app development.&lt;/p&gt;

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

&lt;p&gt;With its AI-powered features and seamless cloud integration, this web-based integrated development environment (IDE) promises to simplify and enhance the development workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Project IDX?
&lt;/h2&gt;

&lt;p&gt;Project IDX is a next-generation, web-based IDE that aims to streamline the development process. Built on the popular Code OSS project and leveraging the robust infrastructure of Google Cloud, Project IDX offers a fully configurable virtual machine (VM) environment right in your browser.&lt;/p&gt;

&lt;p&gt;For more details and to join the open beta, visit the &lt;a href="https://idx.google.com" rel="noopener noreferrer"&gt;Project IDX website&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;This setup ensures reliability, safety, and complete configurability, making it an ideal choice for developers of all levels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the Most of Project IDX
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Get Started Quickly&lt;/strong&gt;&lt;br&gt;
Start new projects or import existing ones from GitHub effortlessly. Use pre-configured templates and choose from popular frameworks and languages like JavaScript, Dart, and soon Python and Go.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Leverage IDX AI for Enhanced Coding&lt;/strong&gt;&lt;br&gt;
Utilize IDX AI for intelligent code completion, translations, and explanations of complex snippets, boosting coding speed and quality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Utilize Built-In Emulators for Mobile Development&lt;/strong&gt;&lt;br&gt;
Test your mobile apps with built-in Android emulators and iOS simulators, previewing changes in real-time within Project IDX.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Seamless Deployment with Firebase Hosting&lt;/strong&gt;&lt;br&gt;
Deploy web and Flutter projects directly to Firebase Hosting with a few clicks, ensuring fast, secure, and global hosting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Collaborate with Ease&lt;/strong&gt;&lt;br&gt;
Use the experimental collaborative workspace sharing to invite team members, enabling real-time collaboration on code, terminals, emulators, and more.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Google's Project IDX is set to transform the development landscape with its innovative, AI-powered, and cloud-based IDE. Now in open beta, it's the perfect time to explore its capabilities and integrate it into your development workflow.&lt;/p&gt;

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

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bio.link/devarshishimpi" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/how-fast-is-bunsh-after-all" rel="noopener noreferrer"&gt;How Fast Is Bun.sh in 2024 After All?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/how-to-install-and-setup-a-ghost-blog-on-aws-lightsail" rel="noopener noreferrer"&gt;How to Install and Set Up a Ghost Blog on AWS Lightsail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog//deploy-minio-on-amazon-eks-self-host-s3-storage" rel="noopener noreferrer"&gt;Deploy MinIO on Amazon EKS and use your S3 Compatible Storage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>news</category>
      <category>idx</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Deploy MinIO on Amazon EKS and use your S3 Compatible Storage</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Thu, 23 May 2024 08:06:09 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/deploy-minio-on-amazon-eks-and-use-your-s3-compatible-storage-ld2</link>
      <guid>https://forem.com/devarshishimpi/deploy-minio-on-amazon-eks-and-use-your-s3-compatible-storage-ld2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Tired of the limitations and costs of AWS S3? Unlock a powerful alternative with MinIO, seamlessly integrated with Amazon EKS. This guide provides a step-by-step walkthrough to deploy MinIO, a scalable, multi-tenant object storage solution, on Amazon EKS in just 15 minutes.&lt;/p&gt;

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

&lt;p&gt;Amazon EKS, a managed Kubernetes service on AWS, simplifies Kubernetes management, while MinIO, available on the AWS Marketplace, brings robust object storage capabilities.  Imagine handling terabytes to exabytes of data, all while isolating tenants in their own namespaces, all without the confines of S3.&lt;/p&gt;

&lt;p&gt;This guide empowers you to ditch AWS S3 and embrace a superior alternative. Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before diving in, ensure you have the following tools installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;awscli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eksctl&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have these three configuration parameters handy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AWS Account Number:&lt;/strong&gt; Find it in the AWS Console or using this command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_ACCOUNT_NUMBER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;aws sts get-caller-identity &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Account"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$AWS_ACCOUNT_NUMBER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Region:&lt;/strong&gt; For example, &lt;code&gt;us-west-2&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cluster Name:&lt;/strong&gt; For example, &lt;code&gt;minio-cluster&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Initial Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Set Up Cluster
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;New Cluster:&lt;/strong&gt;&lt;br&gt;
Replace &lt;code&gt;&amp;lt;CLUSTER_NAME&amp;gt;&lt;/code&gt; and execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eksctl create cluster &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; &amp;lt;CLUSTER_NAME&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--version&lt;/span&gt; 1.21 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--node-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c6i.24xlarge &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--nodes-min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--nodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--nodes-max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--zones&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-west-2a,us-west-2b,us-west-2c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Install AWS EBS CSI Driver
&lt;/h3&gt;

&lt;p&gt;This driver allows using gp3 and sc1 storage types within EKS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="s2"&gt;"github.com/kubernetes-sigs/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.5"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cluster Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create IAM Policy
&lt;/h3&gt;

&lt;p&gt;Replace &lt;code&gt;&amp;lt;CLUSTER_NAME&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;AWS_ACCOUNT_NUMBER&amp;gt;&lt;/code&gt; in &lt;code&gt;iam-policy.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws iam create-policy &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--policy-name&lt;/span&gt; minio-eks-&amp;lt;CLUSTER_NAME&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--policy-document&lt;/span&gt; file://iam-policy.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Create an OIDC Provider
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eksctl utils associate-iam-oidc-provider &lt;span class="nt"&gt;--region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-west-2 &lt;span class="nt"&gt;--cluster&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;CLUSTER_NAME&amp;gt; &lt;span class="nt"&gt;--approve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Create Trust, Role, and Service Account
&lt;/h3&gt;

&lt;p&gt;For MinIO Operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eksctl create iamserviceaccount &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--name&lt;/span&gt; minio-operator &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--namespace&lt;/span&gt; minio-operator &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--cluster&lt;/span&gt; &amp;lt;CLUSTER_NAME&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--attach-policy-arn&lt;/span&gt; arn:aws:iam::&amp;lt;AWS_ACCOUNT_NUMBER&amp;gt;:policy/minio-eks-&amp;lt;CLUSTER_NAME&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--approve&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--override-existing-serviceaccounts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For AWS EBS CSI Driver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eksctl create iamserviceaccount 
   &lt;span class="nt"&gt;--name&lt;/span&gt; ebs-csi-controller-sa 
   &lt;span class="nt"&gt;--namespace&lt;/span&gt; kube-system 
   &lt;span class="nt"&gt;--cluster&lt;/span&gt; &amp;lt;CLUSTER_NAME&amp;gt; 
   &lt;span class="nt"&gt;--attach-policy-arn&lt;/span&gt; arn:aws:iam::&amp;lt;AWS_ACCOUNT_NUMBER&amp;gt;:policy/minio-eks-&amp;lt;CLUSTER_NAME&amp;gt; 
   &lt;span class="nt"&gt;--approve&lt;/span&gt; 
   &lt;span class="nt"&gt;--override-existing-serviceaccounts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing MinIO
&lt;/h2&gt;

&lt;p&gt;Deploy the MinIO Operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-k&lt;/span&gt; github.com/miniohq/marketplace/eks/resources
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Accessing MinIO
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Retrieve the JWT for Operator Console
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minio-operator get secret &lt;span class="si"&gt;$(&lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minio-operator get serviceaccount console-sa &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.secrets[0].name}"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.data.token}"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Port Forward to Operator Console
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minio-operator port-forward svc/console 9090
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:9090" rel="noopener noreferrer"&gt;http://localhost:9090&lt;/a&gt; in your browser and log in with the retrieved JWT.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Create a Tenant
&lt;/h3&gt;

&lt;p&gt;Log in and create your first tenant, specifying the desired size and storage type.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Congratulations! In just 15 minutes, you've successfully deployed MinIO on Amazon EKS, paving the way for a robust and scalable object storage solution.  This guide offers a powerful starting point for migrating away from AWS S3, empowering you with flexibility, cost-efficiency, and a superior alternative for your data storage needs. &lt;/p&gt;

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bio.link/devarshishimpi" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/setting-up-an-ubuntu-ec2-instance-from-scratch-on-aws" rel="noopener noreferrer"&gt;Setting Up An Ubuntu EC2 Instance From Scratch on AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/how-to-install-and-setup-a-ghost-blog-on-aws-lightsail" rel="noopener noreferrer"&gt;How to Install and Set Up a Ghost Blog on AWS Lightsail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/creating-your-first-droplet-digitalocean-tutorials" rel="noopener noreferrer"&gt;Creating Your First Droplet - DigitalOcean Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>eks</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>How To Create An AI Chatbot with Google GEMINI using Node.js</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Wed, 17 Apr 2024 10:29:23 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/how-to-create-an-ai-chatbot-with-google-gemini-using-nodejs-pn6</link>
      <guid>https://forem.com/devarshishimpi/how-to-create-an-ai-chatbot-with-google-gemini-using-nodejs-pn6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Generative AI has become a popular topic in the field of technology over the past year. Many developers are creating interesting projects using this technology. Google has developed its own generative AI model called Gemini.&lt;/p&gt;

&lt;p&gt;In this article, we will be building a simple Node.js ChatBot and integrating Google Gemini into it. We will utilize the Google Gemini SDK for this purpose.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Gemini?
&lt;/h3&gt;

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

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Gemini_(language_model)" rel="noopener noreferrer"&gt;Google Gemini&lt;/a&gt; is an advanced AI model developed by Google AI. Unlike traditional AI models, Gemini is not limited to processing text alone. It can also comprehend and operate on diverse formats such as code, audio, images, and video. This feature opens up exciting possibilities for your Node.js projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Creating a Node.js Project
&lt;/h4&gt;

&lt;p&gt;To begin our project, we need to set up a Node.js environment. Let's create a new Node.js project by running the following command in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This command will initialize a new Node.js project.&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Add boilerplate from Google AI Studio
&lt;/h4&gt;

&lt;p&gt;Get the initial code from &lt;a href="https://aistudio.google.com/app/prompts/new_chat" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;, then click &lt;strong&gt;Get Code&lt;/strong&gt; and copy the code for the Node.js and paste it into a file called as &lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Also, make sure to generate an API key from the AI Studio. Select your Google Cloud project and click &lt;strong&gt;Create&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Now, We'll install the required dependencies of our project.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @google/generative-ai ora chalk prompt-sync
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The packages are used for the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;@google/generative-ai&lt;/code&gt;: Google's package for generative AI tasks like text and image generation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ora&lt;/code&gt;: Creates loading spinners and progress bars in the terminal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chalk&lt;/code&gt;: Styles text in the terminal with colors and styles.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prompt-sync&lt;/code&gt;: Allows synchronous user input prompts in Node.js applications.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  4. Create a chatbot and customize it
&lt;/h4&gt;

&lt;p&gt;In the initial version of our chatbot script, we relied on CommonJS require statements for importing modules. However, in the final iteration, we embraced ES6 import syntax for cleaner and more modern code organization.&lt;/p&gt;

&lt;p&gt;Go to your &lt;code&gt;package.json&lt;/code&gt; file and add the following line below &lt;code&gt;"main": "index.js",&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It should look something like this (Top section only):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"devarshishimpi-google-gemini-nodejs-chatbot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Simple Google Gemini ChatBot for Nodejs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Error: no test specified&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; exit 1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and continued...&lt;/p&gt;

&lt;p&gt;Then, we update from using &lt;code&gt;const&lt;/code&gt; to using &lt;code&gt;import&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenerativeAI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HarmCategory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HarmBlockThreshold&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/generative-ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;chalk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chalk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ora&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ora&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prompt-sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;One significant enhancement was the introduction of a user input mechanism using the &lt;code&gt;prompt-sync&lt;/code&gt; library. This allowed users to interact with the chatbot in real-time, entering their messages directly into the console.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;promptSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, we customize the user interface with &lt;code&gt;ora&lt;/code&gt; and &lt;code&gt;chalk&lt;/code&gt; and make it more user responsive and easy to use&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;promptSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;exit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Goodbye!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AI:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, we add some error handling logic to our code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;red&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AI Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AI:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  5. Final Output
&lt;/h4&gt;

&lt;p&gt;Please find the final code for project at, please star ⭐️ the repo if you found it useful:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/devarshishimpi" rel="noopener noreferrer"&gt;
        devarshishimpi
      &lt;/a&gt; / &lt;a href="https://github.com/devarshishimpi/google-gemini-nodejs-chatbot" rel="noopener noreferrer"&gt;
        google-gemini-nodejs-chatbot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Simple Google Gemini ChatBot for Nodejs
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Google Gemini Node.js Chatbot&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Simple Google Gemini ChatBot for Nodejs&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install @google/generative-ai ora chalk prompt-sync&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Replace the &lt;code&gt;API_KEY&lt;/code&gt; in &lt;code&gt;index.js&lt;/code&gt; with your own API key.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;node index.js&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Contributing&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Please view the &lt;a href="https://github.com/devarshishimpi/google-gemini-nodejs-chatbot/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; for more information.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/devarshishimpi/google-gemini-nodejs-chatbot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Output:&lt;/p&gt;

&lt;p&gt;We use &lt;code&gt;node index.js&lt;/code&gt; to run our code. Make sure to replace &lt;code&gt;YOUR_API_KEY&lt;/code&gt; with your generated API Key from Google API Studio.&lt;/p&gt;

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

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

&lt;p&gt;Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bio.link/devarshishimpi" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/top-ten-vscode-extensions-you-need-in-twentytwentytwo" rel="noopener noreferrer"&gt;Top 10 VS CODE Extensions You Need In 2022!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/easiest-way-to-install-wordpress-for-beginners" rel="noopener noreferrer"&gt;Easiest Way to Install WordPress Locally for Beginners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/what-is-digitalocean-everything-you-need-to-know" rel="noopener noreferrer"&gt;What is DigitalOcean? - Everything You Need to Know&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>ai</category>
    </item>
    <item>
      <title>WordPress.com vs. WordPress.org – The Differences &amp; Which To Choose</title>
      <dc:creator>Devarshi Shimpi</dc:creator>
      <pubDate>Sat, 17 Feb 2024 13:05:06 +0000</pubDate>
      <link>https://forem.com/devarshishimpi/wordpresscom-vs-wordpressorg-the-differences-which-to-choose-422h</link>
      <guid>https://forem.com/devarshishimpi/wordpresscom-vs-wordpressorg-the-differences-which-to-choose-422h</guid>
      <description>&lt;p&gt;Are WordPress.com and WordPress.org the same? It's a question that may seem obvious, but the truth is that those three little letters after the period make a huge difference and could impact the success of your website in the future.&lt;/p&gt;

&lt;p&gt;So, what are the differences between WordPress.com and WordPress.org? Besides sharing the name 'WordPress', there are significant differences to consider when choosing the platform for your website.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is The Difference Between WordPress.com and WordPress.org?
&lt;/h2&gt;

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

&lt;p&gt;To make things clear, let's cover all the differences between WordPress.com and WordPress.org, starting with the fundamental difference:&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fundamental Difference
&lt;/h3&gt;

&lt;p&gt;WordPress.org is managed by the non-profit WordPress Foundation, and it is a self-hosted content management system. This means that you can install it anywhere and buy your own domain to set up a website. It is not only a self-hosted content management system, but it is also the world's leading content management system.&lt;/p&gt;

&lt;p&gt;WordPress.com, on the other hand, is essentially the largest WordPress-as-a-Service (WaaS) platform owned by Automattic, the company run by WordPress co-founder, Matt Mullenweg. It is powered by the WordPress.org open-source software.&lt;/p&gt;

&lt;h3&gt;
  
  
  TL;DR – WordPress.com vs. WordPress.org Differences
&lt;/h3&gt;

&lt;p&gt;In short, WordPress.com is a limited version of WordPress.org that has been simplified for a different demographic.&lt;/p&gt;

&lt;p&gt;The main differences between the two are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WordPress.com:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Hosting is provided by WordPress.com&lt;/li&gt;
&lt;li&gt;  Limited monetization options - no advertising options other than the "official" WordPress.com advertising program&lt;/li&gt;
&lt;li&gt;  Limited plugin installation or updates on the free plan (higher-tier plans have similar limitations)&lt;/li&gt;
&lt;li&gt;  Limited choice of free themes&lt;/li&gt;
&lt;li&gt;  Limited customization options&lt;/li&gt;
&lt;li&gt;  No Google Analytics on the free plan&lt;/li&gt;
&lt;li&gt;  Upgrade required for the use of custom domains without the WordPress.com subdomain&lt;/li&gt;
&lt;li&gt;  No eCommerce features or integrated payment options on the free plan&lt;/li&gt;
&lt;li&gt;  No membership websites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;WordPress.org:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Requires external hosting (e.g., using a cloud provider or a shared hosting service)&lt;/li&gt;
&lt;li&gt;  More flexibility in monetization options&lt;/li&gt;
&lt;li&gt;  Unrestricted plugin installation and updates&lt;/li&gt;
&lt;li&gt;  Access to a wide range of free and premium themes&lt;/li&gt;
&lt;li&gt;  Customization options are not limited&lt;/li&gt;
&lt;li&gt;  Google Analytics and other tracking tools can be used&lt;/li&gt;
&lt;li&gt;  Ability to use custom domains&lt;/li&gt;
&lt;li&gt;  eCommerce features and integrated payment options available&lt;/li&gt;
&lt;li&gt;  Membership websites can be created&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Verdict
&lt;/h3&gt;

&lt;p&gt;While WordPress.com may have its advantages, there are more limitations compared to WordPress.org. Your decision on whether to choose WordPress.com or WordPress.org should be based on the requirements and goals of your website.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pricing and Cost Differences
&lt;/h3&gt;

&lt;p&gt;Budget is always one of the first things you have to figure out when you’re building something. In this case, there are big differences between the pricing and costs of WordPress.com and WordPress.org, so to help you plan your budget better, we have broken down both solutions.&lt;/p&gt;

&lt;p&gt;WordPress.com offers four different pricing plans that can be paid annually, upfront, or monthly.&lt;/p&gt;

&lt;p&gt;Here’s a detailed pricing breakdown for WordPress.com&lt;/p&gt;

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

&lt;p&gt;Besides these, WordPress.com does offer a free plan, and all you have to do is buy the domain. However, you will have their subdomain displayed e.g &lt;a href="http://www.yourwebsite.wordpress.com" rel="noopener noreferrer"&gt;www.yourwebsite.wordpress.com&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;When it comes to WordPress.org, it’s completely free to use. However, there are other costs that WordPress.org doesn’t cover, which WordPress.com covers for you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hosting&lt;/strong&gt; – You can either set up a server with a cloud provider like &lt;a href="https://go.devarshi.dev/digitalocean-200" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt;, &lt;a href="https://www.linode.com/" rel="noopener noreferrer"&gt;Linode&lt;/a&gt; or &lt;a href="https://www.vultr.com/?ref=9043736" rel="noopener noreferrer"&gt;Vultr&lt;/a&gt; or &lt;a href="https://railway.app?referralCode=tXRquz" rel="noopener noreferrer"&gt;using a shared hosting service&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; — Depending on your hosting, you might need some premium security features or plugins that can cost up to $250 per year.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Premium themes&lt;/strong&gt; — there are free ones, but to get the most out of WordPress.org, you’ll probably want to go with premium themes. They usually cost up to $150 per year.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Premium plugins&lt;/strong&gt; — another optional thing, but if you’re serious about scaling your website fast, you will probably want to go with some premium plugins like Rank Math for SEO.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Ease of Use
&lt;/h3&gt;

&lt;p&gt;Both WordPress.com and WordPress.org have a learning curve, but the ease of use may vary depending on your level of experience and needs.&lt;/p&gt;

&lt;p&gt;WordPress.com is designed for blogging, and its setup is more straightforward. However, it comes with limitations and fewer options for customization.&lt;/p&gt;

&lt;p&gt;WordPress.org offers more freedom and flexibility but may require more technical expertise to set up and configure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plugins
&lt;/h3&gt;

&lt;p&gt;Plugins play a crucial role in extending the functionality of your website. Here's how plugins are handled on WordPress.com and WordPress.org:&lt;/p&gt;

&lt;p&gt;WordPress.com restricts plugin usage to the Business plan. On the free plan and lower-tier plans, you won't have the ability to install or upload plugins. This limits your control over the website's features.&lt;/p&gt;

&lt;p&gt;With WordPress.org, you have no limitations when it comes to plugins. You can freely install and configure any plugin, whether free or premium, to customize your website.&lt;/p&gt;

&lt;h2&gt;
  
  
  After Action Report – Use WordPress.org for Maximum Versatility &amp;amp; Control
&lt;/h2&gt;

&lt;p&gt;Although both platforms have their advantages and disadvantages, there's no question that WordPress.org is the best solution for businesses that are already established or planning significant growth.&lt;/p&gt;

&lt;p&gt;With WordPress.org, you have complete control over your website. You can choose from a vast selection of addons and plugins to integrate various functionalities, customize themes, and have full control over your website's appearance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Happy Coding!!!
&lt;/h2&gt;

&lt;p&gt;Thank you for reading! Feel free to check out my other blog posts and visit my socials!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bio.link/devarshishimpi" rel="noopener noreferrer"&gt;Profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/devarshi-shimpi" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devarshishimpi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/@devarshishimpi" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshishimpi.hashnode.dev" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devarshishimpi"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Read more
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/creating-your-first-droplet-digitalocean-tutorials" rel="noopener noreferrer"&gt;Creating Your First Droplet - DigitalOcean Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/top-ten-vscode-extensions-you-need-in-twentytwentytwo" rel="noopener noreferrer"&gt;Top 10 VS CODE Extensions You Need In 2022!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devarshi.dev/blog/setting-up-an-ubuntu-ec2-instance-from-scratch-on-aws" rel="noopener noreferrer"&gt;Setting Up An Ubuntu EC2 Instance From Scratch on AWS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wordpress</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
