<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Muhammad Awais</title>
    <description>The latest articles on DEV Community by Muhammad Awais (@webtoolshub).</description>
    <link>https://dev.to/webtoolshub</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3944066%2F439d550c-13e0-4372-9bc9-069de81a6696.png</url>
      <title>DEV Community: Muhammad Awais</title>
      <link>https://dev.to/webtoolshub</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/webtoolshub"/>
    <language>en</language>
    <item>
      <title>How to Add WebMCP to Your Next.js App (Complete 2026 Guide)</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Tue, 23 Jun 2026 04:16:56 +0000</pubDate>
      <link>https://dev.to/webtoolshub/how-to-add-webmcp-to-your-nextjs-app-complete-2026-guide-pbp</link>
      <guid>https://dev.to/webtoolshub/how-to-add-webmcp-to-your-nextjs-app-complete-2026-guide-pbp</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frvkfza5dmfu9ix33h18z.webp" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frvkfza5dmfu9ix33h18z.webp" alt="How to Add WebMCP to Your Next.js App: Complete Setup Guide (2026)" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
I was watching Gemini in Chrome try to use a Next.js app I'd built. The agent was taking screenshots, guessing which input field was "search," clicking in the wrong places, hallucinating button labels.&lt;/p&gt;

&lt;p&gt;It was painful to watch. Like watching someone read a book through a foggy window.&lt;/p&gt;

&lt;p&gt;That's the exact problem &lt;strong&gt;WebMCP&lt;/strong&gt; was built to solve.&lt;/p&gt;

&lt;p&gt;WebMCP is a W3C draft standard that adds a &lt;code&gt;navigator.modelContext&lt;/code&gt; API to browsers. Instead of an AI agent scraping your DOM and guessing what your app does, your Next.js app &lt;em&gt;tells&lt;/em&gt; the agent exactly what it can do — in structured, machine-readable terms. The agent calls a function, gets clean data, moves on.&lt;/p&gt;

&lt;p&gt;No screenshots. No broken selectors. No hallucinations.&lt;/p&gt;

&lt;p&gt;In this guide: what WebMCP actually is, how it differs from Anthropic's MCP, and a complete step-by-step implementation in Next.js App Router with working code.&lt;/p&gt;


&lt;h2&gt;
  
  
  WebMCP vs MCP — Clear This Up First
&lt;/h2&gt;

&lt;p&gt;This confuses a lot of developers. One sentence each:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anthropic's MCP&lt;/strong&gt; runs server-side. Your AI agent connects to a backend over JSON-RPC to access databases, file systems, or external APIs. Runs outside the browser entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebMCP&lt;/strong&gt; runs client-side, inside the browser tab. Your site registers tools with &lt;code&gt;navigator.modelContext&lt;/code&gt;, and in-browser agents discover and call them locally. No separate server. No extra auth. The agent uses whatever session the logged-in user already has.&lt;/p&gt;

&lt;p&gt;They're complementary, not competing. A flight booking site might use WebMCP so browser agents can search flights on the front end, while also running an MCP server so Claude or GPT can book flights via API on the back end.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Anthropic MCP&lt;/th&gt;
&lt;th&gt;WebMCP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where it runs&lt;/td&gt;
&lt;td&gt;Server-side&lt;/td&gt;
&lt;td&gt;Browser tab&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;JSON-RPC over stdio/HTTP&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;navigator.modelContext&lt;/code&gt; API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Separate auth required&lt;/td&gt;
&lt;td&gt;Uses existing browser session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend needed?&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No (zero backend)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who made it&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;W3C (Google + Microsoft)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser support&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Chrome 146+ (flag), Edge 147+ (flag)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The W3C published the WebMCP Draft Community Group Report on &lt;strong&gt;February 10, 2026&lt;/strong&gt;. Chrome 146 shipped the first implementation behind a feature flag. All four major browser vendors are at the table — Google, Microsoft, Mozilla, Apple. That's a strong signal.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Two APIs — Declarative vs Imperative
&lt;/h2&gt;

&lt;p&gt;WebMCP gives you two ways to expose tools.&lt;/p&gt;
&lt;h3&gt;
  
  
  Declarative API — HTML Attributes (2 minutes to ship)
&lt;/h3&gt;

&lt;p&gt;Already have HTML forms? Add two attributes:&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;form&lt;/span&gt;
  &lt;span class="na"&gt;toolname=&lt;/span&gt;&lt;span class="s"&gt;"searchProducts"&lt;/span&gt;
  &lt;span class="na"&gt;tooldescription=&lt;/span&gt;&lt;span class="s"&gt;"Search the product catalog by keyword and category. Returns matching products with price and availability."&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"query"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Search..."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;select&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"category"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;All categories&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"electronics"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Electronics&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/select&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"maxPrice"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Search&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. An agent sees a &lt;code&gt;searchProducts&lt;/code&gt; tool with typed parameters inferred from your form fields. Zero JavaScript needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use for:&lt;/strong&gt; search forms, filters, contact forms, newsletter signups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Imperative API — registerTool()
&lt;/h3&gt;

&lt;p&gt;For dynamic interactions, stateful logic, or multi-step flows:&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;modelContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerTool&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;getUserDashboard&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="s2"&gt;Get the current user's dashboard summary including recent orders, wishlist count, and loyalty points.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&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;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;includeOrders&lt;/span&gt;&lt;span class="p"&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;boolean&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;Include last 5 orders in the response&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;required&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;async&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;includeOrders&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&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-Type&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;includeOrders&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;if ('modelContext' in navigator)&lt;/code&gt; check is not optional. Browsers without WebMCP support shouldn't throw errors — they should degrade gracefully. The JSON Schema in &lt;code&gt;inputSchema&lt;/code&gt; is the same format Claude, GPT, and Gemini already use for function calling. WebMCP speaks the language LLMs already understand.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-Step: Next.js App Router Implementation
&lt;/h2&gt;

&lt;p&gt;Let's wire this into a real Next.js 15 project. I'll use a product search app as the example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — Install the Polyfill
&lt;/h3&gt;

&lt;p&gt;Chrome 146+ has WebMCP behind a flag. Edge 147+ too. Everyone else needs the polyfill:&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; @mcp-b/global @mcp-b/react-webmcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@mcp-b/react-webmcp&lt;/code&gt; gives you the &lt;code&gt;useWebMCP&lt;/code&gt; hook, which handles registration and cleanup automatically when components mount/unmount.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Initialize in Root Layout
&lt;/h3&gt;

&lt;p&gt;Create a Client Component that initializes the polyfill once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// components/WebMCPProvider.tsx&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;WebMCPProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;modelContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mcp-b/global&lt;/span&gt;&lt;span class="dl"&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;initializeWebMCPPolyfill&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;initializeWebMCPPolyfill&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="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add it to &lt;code&gt;app/layout.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WebMCPProvider&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;@/components/WebMCPProvider&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;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&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;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;WebMCPProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;WebMCPProvider&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;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&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;h3&gt;
  
  
  Step 3 — Register Tools in Page Components
&lt;/h3&gt;

&lt;p&gt;Key principle: &lt;strong&gt;register tools when the UI is visible, unregister when the user leaves.&lt;/strong&gt; The &lt;code&gt;useWebMCP&lt;/code&gt; hook handles this automatically via AbortController.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/products/ProductsPageTools.tsx&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useWebMCP&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;@mcp-b/react-webmcp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&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;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductsPageTools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useWebMCP&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;searchProducts&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;Search the product catalog. Returns products with name, price, rating, and stock status. Use when the user asks to find, browse, or filter products.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search keywords — e.g. "wireless headphones"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product category filter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;maxPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Maximum price in USD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;inStock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Only return in-stock items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxPrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inStock&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;params&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;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;category&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="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;category&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;maxPrice&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="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxPrice&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;inStock&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="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inStock&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;1&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/products?&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// renders nothing — just manages tool registration&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drop &lt;code&gt;&amp;lt;ProductsPageTools /&amp;gt;&lt;/code&gt; inside your products page. When the component mounts, the tool registers. Navigate away — it automatically unregisters. Clean, no memory leaks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 — Enable the Chrome Flag and Test
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open Chrome 146+&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;chrome://flags&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Search for "webmcp" → set &lt;strong&gt;"Enable WebMCP for testing"&lt;/strong&gt; to Enabled&lt;/li&gt;
&lt;li&gt;Relaunch Chrome&lt;/li&gt;
&lt;li&gt;Open your app (localhost or HTTPS — plain HTTP won't work in production)&lt;/li&gt;
&lt;li&gt;Open DevTools (F12) → Console → run: &lt;code&gt;navigator.modelContext&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you see an object (not &lt;code&gt;undefined&lt;/code&gt;), WebMCP is active ✅&lt;/li&gt;
&lt;li&gt;Install the &lt;strong&gt;Model Context Tool Inspector&lt;/strong&gt; extension from the Chrome Web Store — it shows registered tools and lets you invoke them with test inputs without needing an actual AI agent&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last step saved me ~40 minutes of debugging on my first implementation. Highly recommend.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas That Bit Me (So They Don't Bite You)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Single-Tab Scope
&lt;/h3&gt;

&lt;p&gt;Tools only exist while the page is open. Navigate away — tools are gone. Refresh — they re-register. This is intentional (security), but make your tool descriptions rich and self-explanatory. The agent can't know what tools exist without visiting your page first.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. provideContext() Is Gone
&lt;/h3&gt;

&lt;p&gt;Earlier drafts had a &lt;code&gt;provideContext()&lt;/code&gt; method for passing page state to agents. &lt;strong&gt;It was removed in March 2026.&lt;/strong&gt; If you see tutorials using it, they're outdated.&lt;/p&gt;

&lt;p&gt;The current pattern: bake context into your tool's &lt;code&gt;description&lt;/code&gt; string directly.&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;// ❌ Old (removed)&lt;/span&gt;
&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provideContext&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Current&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCurrentUser&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="nf"&gt;useWebMCP&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;getUserOrders&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="s2"&gt;`Get recent orders for the currently logged-in user (ID: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;). Returns last 10 orders with status and tracking.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Tightly Coupled React State Won't Work
&lt;/h3&gt;

&lt;p&gt;Tool handlers don't have access to React state or Zustand stores. If your app logic is buried in component state, handlers will run with stale data.&lt;/p&gt;

&lt;p&gt;Fix: put data-fetching logic in a shared service layer (plain functions, not hooks) and call it from both your UI and WebMCP handlers.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The 50-Tool Soft Limit
&lt;/h3&gt;

&lt;p&gt;No hard cap in the spec, but stay under 50 tools per page. Each tool definition gets included in the agent's context window. Too many tools → bloated context → slow agent reasoning. Expose the actions that actually matter for agent workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. HTTPS Is Mandatory in Production
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;localhost&lt;/code&gt; gets a pass in dev. In production — HTTPS only. Custom local domains like &lt;code&gt;myapp.test&lt;/code&gt; need a self-signed cert or ngrok.&lt;/p&gt;




&lt;h2&gt;
  
  
  Browser Support — Honest Picture (June 2026)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Browser&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Chrome 146+ Stable&lt;/td&gt;
&lt;td&gt;✅ Behind flag (&lt;code&gt;enable-webmcp-testing&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edge 147+&lt;/td&gt;
&lt;td&gt;✅ Behind flag (same as Chrome)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chrome 149&lt;/td&gt;
&lt;td&gt;🔜 Public Origin Trial (no flag needed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Firefox&lt;/td&gt;
&lt;td&gt;🔄 In W3C Working Group, no timeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Safari&lt;/td&gt;
&lt;td&gt;🔄 Bug-tracker entry, no commitment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mainstream AI agents (Claude Desktop, ChatGPT, Gemini app) don't call WebMCP tools directly on websites yet as of mid-2026. The working bridge is the &lt;strong&gt;MCP-B browser extension&lt;/strong&gt;, which aggregates WebMCP tools from open tabs and forwards them to local MCP clients.&lt;/p&gt;

&lt;p&gt;The realistic timeline: late 2026 for Chrome Stable with WebMCP on by default.&lt;/p&gt;




&lt;h2&gt;
  
  
  Is It Worth Building Now?
&lt;/h2&gt;

&lt;p&gt;Cost: a few hours of work. The polyfill handles cross-browser fallback. The &lt;code&gt;useWebMCP&lt;/code&gt; hook handles cleanup. When Chrome flips the default switch, your app is already ready.&lt;/p&gt;

&lt;p&gt;Start with one tool — the most important search or filter your users perform. Add &lt;code&gt;useWebMCP&lt;/code&gt;. Test it with the Chrome DevTools inspector. Ship it. Then add more as the spec stabilizes.&lt;/p&gt;

&lt;p&gt;The sites that did responsive design early won mobile. The ones that structured their content early won featured snippets. WebMCP is the same dynamic — and the cost of being early is genuinely low this time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://webmachinelearning.github.io/webmcp/" rel="noopener noreferrer"&gt;W3C WebMCP Draft Spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/WebMCP-org/" rel="noopener noreferrer"&gt;WebMCP-org on GitHub&lt;/a&gt; — polyfill, React hooks, DevTools extension&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/model-context-tool-inspector" rel="noopener noreferrer"&gt;Model Context Tool Inspector&lt;/a&gt; — Chrome extension for testing&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.webtoolshub.online/blog/webmcp-nextjs-setup-guide-2026" rel="noopener noreferrer"&gt;WebToolsHub&lt;/a&gt; — free developer tools and guides.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>webmcp</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Antigravity IDE Black Screen After 2.0 Update - All Fixes (Windows, Mac, Linux)</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Wed, 17 Jun 2026 13:34:25 +0000</pubDate>
      <link>https://dev.to/webtoolshub/antigravity-ide-black-screen-after-20-update-all-fixes-windows-mac-linux-58b1</link>
      <guid>https://dev.to/webtoolshub/antigravity-ide-black-screen-after-20-update-all-fixes-windows-mac-linux-58b1</guid>
      <description>&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%2Fo6ff7tqgg29kwvzjhx21.webp" 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%2Fo6ff7tqgg29kwvzjhx21.webp" alt="Antigravity Black Screen Fix Every Issue Solved (2026 Complete Guide)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Nobody Warned Us About
&lt;/h2&gt;

&lt;p&gt;On May 19, 2026, Google pushed Antigravity 2.0 as a silent automatic update. If you were using Antigravity 1.x that morning, you woke up to one of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A completely black Electron window&lt;/li&gt;
&lt;li&gt;A blank white screen where your IDE should be
&lt;/li&gt;
&lt;li&gt;An IDE that opens but shows no file explorer, no project — just empty panels&lt;/li&gt;
&lt;li&gt;An "Open IDE" button that does absolutely nothing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The frustrating part? Nothing about your machine changed. No driver update, no OS change. It's a packaging bug — and it's fixable in under 10 minutes once you know what actually happened.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Antigravity 2.0 Actually Changed (And Why It Broke Things)
&lt;/h2&gt;

&lt;p&gt;Antigravity 2.0 isn't an update to the IDE. It's an &lt;strong&gt;architecture split&lt;/strong&gt;. Google separated the product into:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Antigravity&lt;/strong&gt; — the new agent-focused launcher (this is what the 2.0 update installed)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Antigravity IDE&lt;/strong&gt; — the actual code editor (this was NOT automatically installed)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When the update ran, it replaced your old IDE executable with the new launcher. The launcher looks for the IDE component, doesn't find it, and renders a blank window.&lt;/p&gt;

&lt;p&gt;Additionally, the AppData path changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# Old path (Antigravity 1.x)
&lt;/span&gt;%&lt;span class="n"&gt;APPDATA&lt;/span&gt;%\&lt;span class="n"&gt;Roaming&lt;/span&gt;\&lt;span class="n"&gt;Antigravity&lt;/span&gt;\

&lt;span class="c"&gt;# New path (Antigravity 2.0+)
&lt;/span&gt;%&lt;span class="n"&gt;APPDATA&lt;/span&gt;%\&lt;span class="n"&gt;Roaming&lt;/span&gt;\&lt;span class="n"&gt;Antigravity&lt;/span&gt; &lt;span class="n"&gt;IDE&lt;/span&gt;\
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your settings, workspace state, extensions — all still in the old folder. The new IDE launches with an empty profile. This is why your file explorer shows nothing even after getting the IDE to open.&lt;/p&gt;




&lt;h2&gt;
  
  
  Version Timeline (Find Where You Are)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Released&lt;/th&gt;
&lt;th&gt;Known Issues&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2.0.1&lt;/td&gt;
&lt;td&gt;May 19, 2026&lt;/td&gt;
&lt;td&gt;Blank/black screen, no IDE access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.0.6&lt;/td&gt;
&lt;td&gt;May 22, 2026&lt;/td&gt;
&lt;td&gt;"Open IDE" button added but often non-functional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.0.10&lt;/td&gt;
&lt;td&gt;May 28, 2026&lt;/td&gt;
&lt;td&gt;Minor stability fixes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.0.11&lt;/td&gt;
&lt;td&gt;June 3, 2026&lt;/td&gt;
&lt;td&gt;Fixed antivirus GPU block + Open IDE button bugs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Check your version: &lt;strong&gt;Help → About&lt;/strong&gt; (if you can get to the menu bar at all).&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 1: Update to 2.0.11
&lt;/h2&gt;

&lt;p&gt;If the menu bar is visible on your blank screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Help → Check for Updates → Install → Restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Critical:&lt;/strong&gt; After closing, kill all processes before relaunching. On Windows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Kill all Antigravity processes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;taskkill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/IM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;antigravity.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/T&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;taskkill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/IM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"antigravity ide.exe"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/T&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then relaunch. Version 2.0.11 fixes the antivirus interference issue and the Open IDE button bugs — two of the most reported problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 2: Clear Cache and Logs (2 Minutes)
&lt;/h2&gt;

&lt;p&gt;Corrupted cache from a bad update or crash causes blank rendering even on a correctly installed IDE.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Kill processes first&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;taskkill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/IM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;antigravity.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/T&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# 2. Navigate and delete&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;APPDATA&lt;/span&gt;&lt;span class="nx"&gt;\Antigravity&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Cache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# 3. Relaunch&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;macOS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pkill &lt;span class="nt"&gt;-f&lt;/span&gt; Antigravity
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Antigravity/logs
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Antigravity/Cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pkill &lt;span class="nt"&gt;-f&lt;/span&gt; antigravity
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/.config/Antigravity/logs ~/.config/Antigravity/Cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Projects and extensions are stored separately — this is safe to run.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 3: Clean Reinstall
&lt;/h2&gt;

&lt;p&gt;When the cache clear doesn't work, a clean reinstall does. Your project files on disk are not touched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows — full removal script:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Kill processes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;taskkill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/IM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;antigravity.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/T&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# 2. Uninstall via winget (if installed that way)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;winget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;uninstall&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Antigravity"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;winget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;uninstall&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Antigravity IDE"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# 3. Or uninstall manually: Settings → Apps → search "Antigravity" → uninstall both&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# 4. Clean up AppData&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;APPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Antigravity"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;APPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Antigravity IDE"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;LOCALAPPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Antigravity"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;LOCALAPPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Antigravity IDE"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;\.antigravity"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# 5. Download fresh installer from antigravity.google and run&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;macOS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Remove app&lt;/span&gt;
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /Applications/Antigravity.app
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /Applications/Antigravity&lt;span class="se"&gt;\ &lt;/span&gt;IDE.app

&lt;span class="c"&gt;# Remove all data&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Antigravity
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Antigravity&lt;span class="se"&gt;\ &lt;/span&gt;IDE
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/.antigravity

&lt;span class="c"&gt;# Remove launch agents if any&lt;/span&gt;
launchctl list | &lt;span class="nb"&gt;grep &lt;/span&gt;antigravity
&lt;span class="c"&gt;# For each result: launchctl remove &amp;lt;name&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux (Ubuntu):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt remove antigravity-ide
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt autoremove
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/.config/Antigravity ~/.antigravity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux (Fedora):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf remove antigravity-ide
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/.config/Antigravity ~/.antigravity

&lt;span class="c"&gt;# After reinstalling, if still black screen:&lt;/span&gt;
antigravity &lt;span class="nt"&gt;--no-sandbox&lt;/span&gt;
&lt;span class="c"&gt;# Fedora 40+ SELinux can block Electron — no-sandbox bypasses it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Fix 4: Open IDE Button Doing Nothing
&lt;/h2&gt;

&lt;p&gt;The launcher and IDE communicate via a local socket. If that connection fails, the button appears to do nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workaround:&lt;/strong&gt; Launch Antigravity IDE directly as a standalone app, bypassing the launcher entirely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Windows — find and launch directly&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$idePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;LOCALAPPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Programs\Antigravity IDE\Antigravity IDE.exe"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$idePath&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="n"&gt;Start-Process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$idePath&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="kr"&gt;else&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="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Not found — check %LOCALAPPDATA%\Programs\"&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;If the shortcut is missing from Start Menu, find the exe at &lt;code&gt;%LOCALAPPDATA%\Programs\Antigravity IDE\&lt;/code&gt; and create a shortcut manually.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 5: File Explorer Missing — AppData Migration
&lt;/h2&gt;

&lt;p&gt;This is the issue most guides completely miss. You get the IDE open, but see an empty workspace with no file explorer because your settings are in the wrong folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Windows — migrate old settings to new location&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$old&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;APPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Antigravity"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;APPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Antigravity IDE"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$old&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="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$new&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="n"&gt;New-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ItemType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$new&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="n"&gt;Copy-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old&lt;/span&gt;&lt;span class="s2"&gt;\*"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Destination&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Settings migrated — restart Antigravity IDE"&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="kr"&gt;else&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="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Old folder not found — may already be migrated"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# macOS / Linux equivalent&lt;/span&gt;
&lt;span class="nv"&gt;OLD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Antigravity
&lt;span class="nv"&gt;NEW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Antigravity&lt;span class="se"&gt;\ &lt;/span&gt;IDE
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NEW&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OLD&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NEW&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running this, restart Antigravity IDE. Extensions, themes, snippets, and workspace state should all come back. Reopen your project folder once via &lt;strong&gt;File → Open Folder&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 6: Antivirus Causing Instant Black Screen (Windows)
&lt;/h2&gt;

&lt;p&gt;Some antivirus configurations block Electron's GPU subprocess. The result is an instantly black window with zero loading.&lt;/p&gt;

&lt;p&gt;Add these paths to your AV exclusions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;C&lt;/span&gt;:\&lt;span class="n"&gt;Users&lt;/span&gt;\&amp;lt;&lt;span class="n"&gt;YourUser&lt;/span&gt;&amp;gt;\&lt;span class="n"&gt;AppData&lt;/span&gt;\&lt;span class="n"&gt;Local&lt;/span&gt;\&lt;span class="n"&gt;Programs&lt;/span&gt;\&lt;span class="n"&gt;Antigravity&lt;/span&gt; &lt;span class="n"&gt;IDE&lt;/span&gt;\
%&lt;span class="n"&gt;APPDATA&lt;/span&gt;%\&lt;span class="n"&gt;Antigravity&lt;/span&gt;
%&lt;span class="n"&gt;APPDATA&lt;/span&gt;%\&lt;span class="n"&gt;Antigravity&lt;/span&gt; &lt;span class="n"&gt;IDE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Windows Defender via PowerShell:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$idePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;LOCALAPPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Programs\Antigravity IDE"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Add-MpPreference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExclusionPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$idePath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Add-MpPreference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExclusionPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;APPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Antigravity"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Add-MpPreference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExclusionPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;APPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Antigravity IDE"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Exclusions added — relaunch Antigravity IDE"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Quick Decision Guide
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Blank screen appeared → Menu bar visible?
  YES → Update to 2.0.11 (Fix 1)
  NO  → Clean reinstall (Fix 3)

After reinstall → IDE opens but empty workspace?
  YES → AppData migration (Fix 5)

Open IDE button → Does nothing?
  YES → Launch IDE directly (Fix 4)

Instantly black on startup → Windows with AV software?
  YES → Add AV exclusions (Fix 6)

None of the above → Clear cache first (Fix 2), then Fix 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  While Your IDE Was Down
&lt;/h2&gt;

&lt;p&gt;I kept working using browser tools that need zero setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.webtoolshub.online/tools/json-to-ts" rel="noopener noreferrer"&gt;JSON → TypeScript&lt;/a&gt;&lt;/strong&gt; — validated config interfaces without the IDE&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.webtoolshub.online/tools/regex-tester-debugger" rel="noopener noreferrer"&gt;Regex Tester&lt;/a&gt;&lt;/strong&gt; — checked patterns in Antigravity log files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.webtoolshub.online/tools/unix-timestamp-converter" rel="noopener noreferrer"&gt;Unix Timestamp Converter&lt;/a&gt;&lt;/strong&gt; — cross-checked log timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything runs in the browser — no data leaves your machine. Useful when you're debugging with config files that have API keys or sensitive data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Full Guide + FAQ
&lt;/h2&gt;

&lt;p&gt;For the complete breakdown including Mac launch agent removal, Ubuntu Wayland fix (&lt;code&gt;--ozone-platform=x11&lt;/code&gt;), Fedora SELinux commands, all 7 FAQs, and version-by-version explanation:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://www.webtoolshub.online/blog/antigravity-black-screen-all-fixes-complete-guide-2026" rel="noopener noreferrer"&gt;Complete Antigravity Black Screen Fix Guide — WebToolsHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If the PowerShell migration script (Fix 5) saved you — drop a reaction. Took me an embarrassing amount of time to figure out that one.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>antigravity</category>
      <category>ide</category>
      <category>googleai</category>
      <category>devtools</category>
    </item>
    <item>
      <title>How to Use OpenCode — The 160K-Star Free Cursor Alternative (2026)</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Tue, 16 Jun 2026 12:21:45 +0000</pubDate>
      <link>https://dev.to/webtoolshub/how-to-use-opencode-the-160k-star-free-cursor-alternative-2026-2696</link>
      <guid>https://dev.to/webtoolshub/how-to-use-opencode-the-160k-star-free-cursor-alternative-2026-2696</guid>
      <description>&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%2F9e8jnw8tjka92e2uryvs.webp" 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%2F9e8jnw8tjka92e2uryvs.webp" alt="How to Use OpenCode — The 160K-Star Free Cursor Alternative (2026)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Originally published on &lt;a href="https://www.webtoolshub.online/blog/opencode-complete-guide-setup-2026" rel="noopener noreferrer"&gt;WebToolsHub&lt;/a&gt; — free browser-based developer tools for modern devs.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;You've probably seen &lt;strong&gt;OpenCode&lt;/strong&gt; trending on your GitHub feed lately. 160,000+ stars. 7.5 million monthly active developers as of June 2026. The kind of growth that makes you stop and actually pay attention.&lt;/p&gt;

&lt;p&gt;I spent three weeks using it on a real Next.js SaaS project before writing this. Not a quick "install and screenshot" job — actual production workflow testing. Here's everything I learned, including the stuff most guides skip.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤔 Wait, What Even Is OpenCode?
&lt;/h2&gt;

&lt;p&gt;Most people assume it's another autocomplete tool like Copilot. It's not.&lt;/p&gt;

&lt;p&gt;OpenCode is a &lt;strong&gt;terminal-native agentic coding assistant&lt;/strong&gt; — it understands your entire project, creates a plan, then executes multi-step tasks autonomously. Think of it as a junior developer who can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read all your project files&lt;/li&gt;
&lt;li&gt;Write new code and edit existing files
&lt;/li&gt;
&lt;li&gt;Run shell commands and install packages&lt;/li&gt;
&lt;li&gt;Execute tests and fix failures&lt;/li&gt;
&lt;li&gt;Explain what it's doing at each step&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The killer feature: &lt;strong&gt;model agnosticism&lt;/strong&gt;. OpenCode connects to 75+ AI providers. Claude, GPT, Gemini, DeepSeek, Groq, and even fully local models via Ollama. You bring your own API keys and pay per token. No $20/month subscription that hits rate limits after two hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 Installation (Pick Your Method)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Method 1: Official Script — Fastest Option
&lt;/h3&gt;

&lt;p&gt;Works on macOS, Linux, WSL. Run this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://opencode.ai/install | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify it worked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;opencode &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# v1.17.4 or later (current as of June 2026)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Method 2: npm
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; opencode-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good if you want version control via your Node.js package manager.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 3: Homebrew (macOS)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;opencode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Method 4: Go Install (Advanced / Compile from Source)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/sst/opencode@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important:&lt;/strong&gt; Since January 9, 2026, Anthropic blocked OpenCode from using Claude via consumer OAuth (Claude Pro/Max). You need an &lt;strong&gt;API key from console.anthropic.com&lt;/strong&gt; if you want Claude models. Gemini 2.5 Pro and DeepSeek V4 are great alternatives — and honestly, Gemini Flash is what I use 80% of the time now.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⚙️ Configure Your AI Provider
&lt;/h2&gt;

&lt;p&gt;Run the interactive setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;opencode auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or manually create &lt;code&gt;.opencode.json&lt;/code&gt; in your home directory or project root:&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;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"google"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gemini-2.5-pro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"providers"&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;"google"&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;"apiKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${GEMINI_API_KEY}"&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;"anthropic"&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;"apiKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${ANTHROPIC_API_KEY}"&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;"openai"&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;"apiKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${OPENAI_API_KEY}"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;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;&lt;strong&gt;Want completely free usage?&lt;/strong&gt; Use Ollama with a local model:&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;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ollama"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"llama3:8b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"providers"&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;"ollama"&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;"baseURL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:11434"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;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;blockquote&gt;
&lt;p&gt;⚠️ Local models are noticeably weaker on multi-step tasks. Great for quick edits, not ideal for complex refactors. Use a frontier model when correctness matters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you're integrating OpenCode into a Next.js project with local AI, the &lt;a href="https://www.webtoolshub.online/blog/ollama-nextjs-local-ai-guide" rel="noopener noreferrer"&gt;Ollama + Next.js guide on WebToolsHub&lt;/a&gt; covers the full setup in detail.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 The Feature Nobody Talks About: LSP Integration
&lt;/h2&gt;

&lt;p&gt;This is OpenCode's most underrated advantage. Native &lt;strong&gt;Language Server Protocol (LSP) integration&lt;/strong&gt; — it automatically spawns the correct language server (TypeScript, Python, Go...) and feeds real compiler diagnostics back to the AI after every edit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; Imagine OpenCode refactoring a Next.js component and introducing a TypeScript type error. Without LSP, the AI doesn't know. With LSP, the error feeds back into the next prompt automatically, and the model self-corrects — no copy-pasting error messages from your terminal.&lt;/p&gt;

&lt;p&gt;In a Builder.io head-to-head test (Claude Sonnet 4.5, identical tasks), OpenCode wrote &lt;strong&gt;21 more tests&lt;/strong&gt; than Claude Code on the same codebase. The LSP feedback loop is a big reason.&lt;/p&gt;

&lt;p&gt;This matters most on &lt;strong&gt;multi-file refactors&lt;/strong&gt; with large TypeScript codebases. If you're working with complex API types, pair this with the &lt;a href="https://www.webtoolshub.online/tools/json-to-ts" rel="noopener noreferrer"&gt;JSON to TypeScript converter&lt;/a&gt; to keep your types accurate as the agent works.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚔️ OpenCode vs Claude Code: The Honest Take
&lt;/h2&gt;

&lt;p&gt;I've used both heavily. Here's my unfiltered take.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where Claude Code Wins
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Speed.&lt;/strong&gt; Builder.io's benchmarks show OpenCode takes ~78% longer per identical task when running the same Claude model. The overhead comes from OpenCode's client-server architecture — even when running locally, the TUI talks to a backend process. If you're doing rapid-fire development, you'll feel that gap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where OpenCode Wins
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Basically everything else:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;OpenCode&lt;/th&gt;
&lt;th&gt;Claude Code&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Pay per token only&lt;/td&gt;
&lt;td&gt;$20/mo + rate limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privacy&lt;/td&gt;
&lt;td&gt;Ollama = fully local&lt;/td&gt;
&lt;td&gt;Everything → Anthropic servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model choice&lt;/td&gt;
&lt;td&gt;75+ providers&lt;/td&gt;
&lt;td&gt;Anthropic only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LSP integration&lt;/td&gt;
&lt;td&gt;✅ First-class&lt;/td&gt;
&lt;td&gt;❌ Not native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Planning mode&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/plan&lt;/code&gt; disables all writes&lt;/td&gt;
&lt;td&gt;✅ Similar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;✅ MIT licensed&lt;/td&gt;
&lt;td&gt;❌ Proprietary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;My actual recommendation:&lt;/strong&gt; Use both. Claude Code for speed-critical production work. OpenCode for experimentation, privacy-sensitive codebases, and when you want model flexibility without burning a subscription.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.webtoolshub.online/blog/claude-code-skills-complete-guide-2026" rel="noopener noreferrer"&gt;Claude Code Skills guide on WebToolsHub&lt;/a&gt; is worth reading too — most of those markdown skill files work in OpenCode with minor edits.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Real Next.js Workflow with OpenCode
&lt;/h2&gt;

&lt;p&gt;This is the actual workflow I use on production projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Initialize Project Context
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-nextjs-app
opencode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the OpenCode session:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This analyzes your codebase, understands your conventions and patterns, and creates a &lt;code&gt;.opencode/&lt;/code&gt; directory with persistent context. &lt;strong&gt;Always do this first.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Use Planning Mode for New Features
&lt;/h3&gt;

&lt;p&gt;Before touching any files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plan
Add rate limiting middleware to all API routes using Upstash Redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OpenCode analyzes your existing routes, checks your dependencies, and produces a detailed implementation plan. Review it before saying "proceed." This 30-second habit saves hours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Give Explicit Scoped Instructions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Refactor&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;UserCard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tsx&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;shadcn&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;Keep&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;existing&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;Don&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;t touch parent components.
Run TypeScript check after making changes.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last line — "run TypeScript check" — is where LSP integration shines. OpenCode runs &lt;code&gt;tsc --noEmit&lt;/code&gt;, sees errors, and fixes them in the same session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Use /undo Liberally
&lt;/h3&gt;

&lt;p&gt;OpenCode takes Git-based snapshots before every change. &lt;code&gt;/undo&lt;/code&gt; reverts instantly. Use it constantly. This is what makes it safe to let the agent work aggressively.&lt;/p&gt;




&lt;h2&gt;
  
  
  💸 What Does OpenCode Actually Cost?
&lt;/h2&gt;

&lt;p&gt;OpenCode itself: &lt;strong&gt;$0, forever, MIT licensed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Model API costs for a typical developer daily use:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 2.5 Flash&lt;/td&gt;
&lt;td&gt;~$0.15/1M tokens&lt;/td&gt;
&lt;td&gt;Quick edits, boilerplate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 2.5 Pro&lt;/td&gt;
&lt;td&gt;~$3.50/1M tokens&lt;/td&gt;
&lt;td&gt;Architecture, refactors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 4.6 (API)&lt;/td&gt;
&lt;td&gt;~$3/1M tokens&lt;/td&gt;
&lt;td&gt;TypeScript-heavy work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 4.6 (API)&lt;/td&gt;
&lt;td&gt;~$15/1M tokens&lt;/td&gt;
&lt;td&gt;Hard multi-file problems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ollama (local)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Privacy-sensitive tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For most developers, Gemini Flash handles 80% of tasks at near-zero cost. Save the heavy models for hard problems. Use the &lt;a href="https://www.webtoolshub.online/tools/llm-api-cost-calculator" rel="noopener noreferrer"&gt;LLM API Cost Calculator on WebToolsHub&lt;/a&gt; to estimate your monthly spend before committing.&lt;/p&gt;




&lt;h2&gt;
  
  
  ❌ Mistakes I See Beginners Make
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Skipping &lt;code&gt;/init&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Without project initialization, OpenCode is guessing about your codebase. Always run &lt;code&gt;/init&lt;/code&gt; first in any new project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Using Llama 3 8B for complex refactors&lt;/strong&gt;&lt;br&gt;
It will disappoint you. Save Ollama for single-file edits. Use Gemini Pro or Claude Sonnet for anything spanning multiple files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Not reviewing the plan&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;/plan&lt;/code&gt; before every large change. Non-negotiable. Reading the plan takes 30 seconds. Reverting a 20-file refactor takes 30 minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Not committing a project-level config&lt;/strong&gt;&lt;br&gt;
Put &lt;code&gt;.opencode.json&lt;/code&gt; in your repo root and commit it. Your team gets consistent model settings automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Ignoring session sharing&lt;/strong&gt;&lt;br&gt;
OpenCode generates shareable links for any session. Massive for async debugging — share the exact session where a bug was introduced.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔮 What's Coming in OpenCode
&lt;/h2&gt;

&lt;p&gt;The H1 2026 shipping velocity has been impressive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Background subagents (multiple agents running in parallel)&lt;/li&gt;
&lt;li&gt;✅ Scout agent for external research&lt;/li&gt;
&lt;li&gt;✅ Desktop app beta (macOS, Windows, Linux)&lt;/li&gt;
&lt;li&gt;🔜 Official plugin marketplace&lt;/li&gt;
&lt;li&gt;🔜 MCP server support (already in beta)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With 85% of developers using AI tools daily and AI generating ~46% of all new code in 2026, the choice of coding agent matters more than ever. OpenCode's bet on model agnosticism and open-source transparency puts it in a strong position for however the AI landscape evolves from here.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⭐ TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenCode&lt;/strong&gt; = free, MIT-licensed, terminal-native AI coding agent&lt;/li&gt;
&lt;li&gt;Connects to 75+ providers — Claude, GPT, Gemini, Ollama&lt;/li&gt;
&lt;li&gt;Native LSP integration for automatic error correction (unique feature)&lt;/li&gt;
&lt;li&gt;~78% slower than Claude Code on identical tasks, but cheaper and more private&lt;/li&gt;
&lt;li&gt;Best workflow: &lt;code&gt;/init&lt;/code&gt; → &lt;code&gt;/plan&lt;/code&gt; → execute → &lt;code&gt;/undo&lt;/code&gt; if needed&lt;/li&gt;
&lt;li&gt;Gemini 2.5 Flash for 80% of tasks, Claude Sonnet 4.6 API for hard TypeScript work&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Want free developer tools that work the same way — fully in your browser, no data sent anywhere?&lt;/strong&gt; Check out &lt;a href="https://www.webtoolshub.online" rel="noopener noreferrer"&gt;WebToolsHub&lt;/a&gt; — 100+ free tools for developers including a &lt;a href="https://www.webtoolshub.online/tools/json-to-ts" rel="noopener noreferrer"&gt;JSON→TypeScript converter&lt;/a&gt;, &lt;a href="https://www.webtoolshub.online/tools/ai-prompt-generator-optimizer" rel="noopener noreferrer"&gt;AI Prompt Optimizer&lt;/a&gt;, &lt;a href="https://www.webtoolshub.online/tools/cron-job-generator" rel="noopener noreferrer"&gt;Cron Job Generator&lt;/a&gt;, and more.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All WebToolsHub tools are 100% client-side — nothing is sent to any server.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://www.webtoolshub.online/blog/opencode-complete-guide-setup-2026" rel="noopener noreferrer"&gt;webtoolshub.online/blog/opencode-complete-guide-setup-2026&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opencode</category>
      <category>ai</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How to Calculate LLM API Cost: Tokens, Pricing &amp; the Formula Every Dev Needs (2026)</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Tue, 16 Jun 2026 07:04:22 +0000</pubDate>
      <link>https://dev.to/webtoolshub/how-to-calculate-llm-api-cost-tokens-pricing-the-formula-every-dev-needs-2026-2h19</link>
      <guid>https://dev.to/webtoolshub/how-to-calculate-llm-api-cost-tokens-pricing-the-formula-every-dev-needs-2026-2h19</guid>
      <description>&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%2F36jhm2dw8wvpm4a2aq3n.webp" 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%2F36jhm2dw8wvpm4a2aq3n.webp" alt="How to Calculate LLM API Cost: Token Counting &amp;amp; AI Pricing Guide (2026)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A friend of mine deployed a customer support chatbot using GPT-4o. Three days later: &lt;strong&gt;$340 in OpenAI charges&lt;/strong&gt;. He had no idea where it came from. He thought a few thousand API calls would cost maybe $10.&lt;/p&gt;

&lt;p&gt;That's the LLM API cost trap — and it gets almost every developer the first time, because nobody actually teaches you the math before you ship.&lt;/p&gt;

&lt;p&gt;This article fixes that. We'll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What tokens actually are (the explanation that's actually useful)&lt;/li&gt;
&lt;li&gt;Why input and output tokens are priced differently — and why it matters&lt;/li&gt;
&lt;li&gt;A side-by-side pricing table for GPT-4o, Claude, Gemini, and others (mid-2026)&lt;/li&gt;
&lt;li&gt;The exact formula to estimate your monthly bill before you deploy&lt;/li&gt;
&lt;li&gt;5 silent cost killers in production AI apps&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;🧮 If you just want the number fast: &lt;a href="https://www.webtoolshub.online/tools/llm-api-cost-calculator" rel="noopener noreferrer"&gt;LLM API Cost Calculator&lt;/a&gt; — free, no signup, runs in your browser.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Is a Token? (The Version That Actually Helps)
&lt;/h2&gt;

&lt;p&gt;Every article says "a token is ~4 characters or 0.75 words." Technically true. Practically useless.&lt;/p&gt;

&lt;p&gt;Here's what you actually need to know: a token is the smallest chunk of text an LLM processes. The tokenizer splits your text using a vocabulary of ~100,000 patterns. Common words are usually 1 token. Rare or long words split into multiple tokens.&lt;/p&gt;

&lt;p&gt;Real examples:&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="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;token&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"Hello world"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"internationalization"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&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;"Muhammad"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="err"&gt;-word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;article&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~&lt;/span&gt;&lt;span class="mi"&gt;650&lt;/span&gt;&lt;span class="err"&gt;–&lt;/span&gt;&lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why does this matter for cost?&lt;/strong&gt; Every API call charges you for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Every token you &lt;em&gt;send&lt;/em&gt; (prompt + conversation history + system prompt)&lt;/li&gt;
&lt;li&gt;Every token the model &lt;em&gt;generates&lt;/em&gt; back&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That friend with the $340 bill? He was passing the full 20-message conversation history on every single turn. By message 20, each API call was using 4,000+ tokens in context before the model even started replying.&lt;/p&gt;




&lt;h2&gt;
  
  
  Input Tokens vs Output Tokens — The Pricing Split
&lt;/h2&gt;

&lt;p&gt;This is the distinction most developers miss and it costs them the most money.&lt;/p&gt;

&lt;p&gt;Providers split pricing into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input tokens&lt;/strong&gt; — everything you send to the model&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output tokens&lt;/strong&gt; — everything the model generates back&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Output tokens are almost always &lt;strong&gt;3–5x more expensive&lt;/strong&gt; than input tokens. Because generating a token requires the model to run a full forward pass for every single character it produces (autoregressive generation). Reading input is one pass. Writing output is N passes.&lt;/p&gt;

&lt;p&gt;Practical impact:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prompt Style&lt;/th&gt;
&lt;th&gt;Input Tokens&lt;/th&gt;
&lt;th&gt;Output Tokens&lt;/th&gt;
&lt;th&gt;Cost Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Summarize in 3 bullets"&lt;/td&gt;
&lt;td&gt;850&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;Low output cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Write a detailed analysis"&lt;/td&gt;
&lt;td&gt;850&lt;/td&gt;
&lt;td&gt;600&lt;/td&gt;
&lt;td&gt;5x more output cost&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Same input. Radically different bill. At 10,000 calls/month, that's hundreds of dollars difference from &lt;em&gt;one word in your prompt&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The lever most developers ignore: &lt;strong&gt;control output length with &lt;code&gt;max_tokens&lt;/code&gt;&lt;/strong&gt;, not just prompt length.&lt;/p&gt;




&lt;h2&gt;
  
  
  LLM API Pricing Table — Mid-2026
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Pricing changes frequently. Always verify at &lt;a href="https://openai.com/api/pricing" rel="noopener noreferrer"&gt;openai.com/api/pricing&lt;/a&gt; and &lt;a href="https://www.anthropic.com/pricing" rel="noopener noreferrer"&gt;anthropic.com/pricing&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input / 1M tokens&lt;/th&gt;
&lt;th&gt;Output / 1M tokens&lt;/th&gt;
&lt;th&gt;Context&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4o&lt;/td&gt;
&lt;td&gt;$2.50&lt;/td&gt;
&lt;td&gt;$10.00&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4o mini&lt;/td&gt;
&lt;td&gt;$0.15&lt;/td&gt;
&lt;td&gt;$0.60&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 4&lt;/td&gt;
&lt;td&gt;$3.00&lt;/td&gt;
&lt;td&gt;$15.00&lt;/td&gt;
&lt;td&gt;200K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Haiku 4.5&lt;/td&gt;
&lt;td&gt;$0.80&lt;/td&gt;
&lt;td&gt;$4.00&lt;/td&gt;
&lt;td&gt;200K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 1.5 Pro&lt;/td&gt;
&lt;td&gt;$1.25&lt;/td&gt;
&lt;td&gt;$5.00&lt;/td&gt;
&lt;td&gt;1M+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 1.5 Flash&lt;/td&gt;
&lt;td&gt;$0.075&lt;/td&gt;
&lt;td&gt;$0.30&lt;/td&gt;
&lt;td&gt;1M+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama 3.3 70B (Groq)&lt;/td&gt;
&lt;td&gt;$0.59&lt;/td&gt;
&lt;td&gt;$0.79&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;GPT-4o mini output tokens are &lt;strong&gt;16x cheaper&lt;/strong&gt; than GPT-4o. For classification, routing, or simple Q&amp;amp;A — this is the switch that changes unit economics entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Formula
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cost per call =
  (input_tokens  / 1_000_000 × input_rate) +
  (output_tokens / 1_000_000 × output_rate)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Worked example&lt;/strong&gt; — Document summarizer on Claude Sonnet 4:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Document:      3,000 tokens  (input)
System prompt:   200 tokens  (input)
Summary output:  400 tokens  (output)

Cost per call:
  Input:  (3,200 / 1,000,000) × $3.00  = $0.0096
  Output: (400   / 1,000,000) × $15.00 = $0.0060
  Total:                                  $0.0156

Monthly (5,000 summaries): $78
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now add conversation history — context grows to 8,000 tokens per call → &lt;strong&gt;$195/month&lt;/strong&gt;. Switch to flagship model → &lt;strong&gt;$600+&lt;/strong&gt;. The math compounds fast.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Count Tokens Before You Send
&lt;/h2&gt;

&lt;p&gt;Don't guess — count. Here's how for each provider:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAI — tiktoken:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tiktoken&lt;/span&gt;

&lt;span class="n"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tiktoken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encoding_for_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your prompt text here&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Token count: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install: &lt;code&gt;pip install tiktoken&lt;/code&gt;. Runs locally, no API call needed. &lt;a href="https://github.com/openai/tiktoken" rel="noopener noreferrer"&gt;Full docs on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude — token counting endpoint:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// No actual generation — just counts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;countTokens&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;claude-sonnet-4-6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;yourPrompt&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://docs.anthropic.com/en/docs/build-with-claude/token-counting" rel="noopener noreferrer"&gt;Anthropic's token counting docs&lt;/a&gt; for tool use + system prompt edge cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick estimate (English text only):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Characters ÷ 4 ≈ tokens&lt;/li&gt;
&lt;li&gt;Words ÷ 0.75 ≈ tokens&lt;/li&gt;
&lt;li&gt;Accuracy drops 20–40% for non-Latin scripts (Arabic, Hindi, Chinese)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5 Mistakes Silently Inflating Your Bill
&lt;/h2&gt;

&lt;p&gt;These show up in almost every AI app I've reviewed. Fix them and you'll typically cut costs 40–60%.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Sending Full Conversation History Every Turn
&lt;/h3&gt;

&lt;p&gt;Each turn adds more input tokens. By turn 20 in a chat, you're paying for 19 previous exchanges you already paid for. Implement a &lt;strong&gt;sliding window&lt;/strong&gt; — keep last N turns only, or summarize old context.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Bloated System Prompts
&lt;/h3&gt;

&lt;p&gt;A 2,000-token system prompt sent with every call = 100M tokens of overhead per day at 50k requests. Cut ruthlessly. Every sentence needs to earn its place.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. No &lt;code&gt;max_tokens&lt;/code&gt; Set
&lt;/h3&gt;

&lt;p&gt;Without a ceiling, the model will be verbose. For classification tasks: 50–100 tokens. For summaries: 200–400 tokens. Always set this.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Flagship Model for Everything
&lt;/h3&gt;

&lt;p&gt;Is your email categorization task worth 16x the cost of GPT-4o mini? Route simple tasks to cheaper models. Reserve GPT-4o / Claude Sonnet for tasks that actually need it. Most teams see &lt;strong&gt;60–70% cost reduction&lt;/strong&gt; from this one change.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Not Using Prompt Caching
&lt;/h3&gt;

&lt;p&gt;If you're sending the same large reference document or knowledge base with every request, you're overpaying. Both Anthropic and OpenAI offer prompt caching in 2026. Anthropic's implementation can save &lt;a href="https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;up to 90% on cached input tokens&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Monthly Cost Estimates
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;App Type&lt;/th&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Monthly Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Support chatbot (2k conversations/day)&lt;/td&gt;
&lt;td&gt;GPT-4o mini, 8 turns avg&lt;/td&gt;
&lt;td&gt;~$18–25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same chatbot&lt;/td&gt;
&lt;td&gt;GPT-4o&lt;/td&gt;
&lt;td&gt;~$280–350&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code review assistant (500 PRs)&lt;/td&gt;
&lt;td&gt;Claude Sonnet 4&lt;/td&gt;
&lt;td&gt;~$23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Doc summarizer (10k docs)&lt;/td&gt;
&lt;td&gt;GPT-4o mini&lt;/td&gt;
&lt;td&gt;~$18–22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content generator (1k articles)&lt;/td&gt;
&lt;td&gt;GPT-4o&lt;/td&gt;
&lt;td&gt;~$263&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Pattern: output-heavy tasks + expensive models = highest cost. Build your own estimate with the &lt;a href="https://www.webtoolshub.online/tools/llm-api-cost-calculator" rel="noopener noreferrer"&gt;LLM API Cost Calculator&lt;/a&gt; — plug in your numbers and it gives you the monthly projection instantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Monitoring in Production
&lt;/h2&gt;

&lt;p&gt;Cost dashboard alone isn't enough — you find out after the damage. Set up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI:&lt;/strong&gt; Hard spend limits + soft alert thresholds in account settings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anthropic:&lt;/strong&gt; Usage API for daily spend data + console budget alerts (available 2026)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App-level:&lt;/strong&gt; Log &lt;code&gt;input_tokens&lt;/code&gt; and &lt;code&gt;output_tokens&lt;/code&gt; from every API response into your own DB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-user limits:&lt;/strong&gt; Rate limits or credit systems at application layer — don't let a single user's session spike your bill&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Treat LLM API cost like database query cost. You wouldn't ship a query without understanding its performance profile.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Token estimate:     word_count / 0.75  OR  char_count / 4
Cost per call:      (in_tok/1M × in_rate) + (out_tok/1M × out_rate)
Biggest cost lever: max_tokens ceiling + model routing
Best cheap models:  GPT-4o mini ($0.60/1M out), Gemini Flash ($0.30/1M out)
Free calculator:    webtoolshub.online/tools/llm-api-cost-calculator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;The math isn't complicated once you know where to look. The $340 chatbot bill wasn't a pricing problem — it was a context management problem. Now you know what to check before you deploy.&lt;/p&gt;

&lt;p&gt;What's your biggest AI API cost optimization? Drop it in the comments — always curious what's working for people in production.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>llm</category>
    </item>
    <item>
      <title>How to Decode a JWT Token Online: The Debug Guide Every Developer Needs (2026)</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Sat, 13 Jun 2026 17:31:25 +0000</pubDate>
      <link>https://dev.to/webtoolshub/how-to-decode-a-jwt-token-online-the-debug-guide-every-developer-needs-2026-5enj</link>
      <guid>https://dev.to/webtoolshub/how-to-decode-a-jwt-token-online-the-debug-guide-every-developer-needs-2026-5enj</guid>
      <description>&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%2F721u8egw25pah06z6y53.webp" 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%2F721u8egw25pah06z6y53.webp" alt="How to Decode a JWT Token Online Complete Guide for Developers (2026)"&gt;&lt;/a&gt;&lt;br&gt;
You're staring at a &lt;code&gt;401 Unauthorized&lt;/code&gt;. Your API is rejecting the token. You paste the JWT somewhere and get back a wall of Base64 that means nothing to you.&lt;/p&gt;

&lt;p&gt;I've wasted entire afternoons on this. Turns out, reading a JWT takes about 10 seconds once you understand the structure. Let me save you the afternoon.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical source:&lt;/strong&gt; This article was originally published at &lt;a href="https://www.webtoolshub.online/blog/how-to-decode-jwt-token-online-complete-guide-2026" rel="noopener noreferrer"&gt;WebToolsHub — How to Decode a JWT Token Online&lt;/a&gt;. That version includes a live free tool, full code examples, and is kept up to date.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  What You'll Learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The exact 3-part JWT structure and what each part contains&lt;/li&gt;
&lt;li&gt;How to decode any JWT in your browser — no install, no account&lt;/li&gt;
&lt;li&gt;The 5 JWT errors that waste the most developer time (and how to fix each one)&lt;/li&gt;
&lt;li&gt;The localStorage mistake that's killed more auth systems than anything else&lt;/li&gt;
&lt;li&gt;HS256 vs RS256 vs ES256 — which one you should actually be using in 2026&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Every JWT Is Three Base64 Strings Separated by Two Dots
&lt;/h2&gt;

&lt;p&gt;That's it. The structure is always:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HEADER.PAYLOAD.SIGNATURE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a real one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsIm5hbWUiOiJBd2FpcyIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTcxNjgwMDAwMCwiZXhwIjoxNzE2ODAzNjAwfQ.mK7tqV9ZjX2pL0nW8sRdUeGfHzCvBwQoTlMxYkIjA1c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste this into the &lt;strong&gt;&lt;a href="https://www.webtoolshub.online/tools/jwt-decoder-verifier" rel="noopener noreferrer"&gt;free JWT Decoder at WebToolsHub&lt;/a&gt;&lt;/strong&gt; and you'll see all three sections decoded instantly. The tool runs 100% in your browser — nothing is sent to any server.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: The Header
&lt;/h2&gt;

&lt;p&gt;Decode the first segment and you get:&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;"alg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HS256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typ"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JWT"&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;&lt;code&gt;alg&lt;/code&gt; is the most important field for debugging. It tells you exactly what's needed to verify this token:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Used For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HS256&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Symmetric (shared secret)&lt;/td&gt;
&lt;td&gt;Monoliths, simple APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RS256&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Asymmetric (public/private key)&lt;/td&gt;
&lt;td&gt;Microservices, OAuth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ES256&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Asymmetric (elliptic curve)&lt;/td&gt;
&lt;td&gt;High-performance APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No signature&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Never accept in production&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you're getting an &lt;code&gt;invalid signature&lt;/code&gt; error, this field is where to start. Mismatched algorithm between your issuer and verifier is one of the top causes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: The Payload (Claims)
&lt;/h2&gt;

&lt;p&gt;Decode the second segment:&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;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user_123"&lt;/span&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;"Awais"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1716800000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1716803600&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;The registered claims you'll see most often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;sub&lt;/code&gt;&lt;/strong&gt; — Subject. Usually the user ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;iss&lt;/code&gt;&lt;/strong&gt; — Issuer. Usually your API's URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;aud&lt;/code&gt;&lt;/strong&gt; — Audience. Must match your server's expected value exactly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;exp&lt;/code&gt;&lt;/strong&gt; — Expiration timestamp (Unix). Your server must validate this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;iat&lt;/code&gt;&lt;/strong&gt; — Issued At timestamp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;nbf&lt;/code&gt;&lt;/strong&gt; — Not Before. Token invalid until this time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;jti&lt;/code&gt;&lt;/strong&gt; — JWT ID. Useful for revocation lists.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Critical rule:&lt;/strong&gt; The payload is Base64URL-encoded, NOT encrypted. Anyone with the token string can decode and read every claim. Never put passwords, credit card numbers, SSNs, or API keys in a JWT payload.&lt;/p&gt;

&lt;p&gt;Those &lt;code&gt;exp&lt;/code&gt; and &lt;code&gt;iat&lt;/code&gt; timestamps are Unix epoch values. When you see &lt;code&gt;"exp": 1716803600&lt;/code&gt; you have no idea if that's past or future. The &lt;a href="https://www.webtoolshub.online/tools/unix-timestamp-converter" rel="noopener noreferrer"&gt;Unix Timestamp Converter at WebToolsHub&lt;/a&gt; converts these instantly. Or in JavaScript:&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;// Check if token is expired&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isExpired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Convert to readable date&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expDate&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiply by 1000 — JavaScript uses milliseconds, JWT uses seconds. Classic gotcha.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3: The Signature
&lt;/h2&gt;

&lt;p&gt;The signature is created from:&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="nc"&gt;HMACSHA256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;base64UrlEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&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="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;base64UrlEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;secret&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If even one character in the header or payload changes, the signature breaks. That's the tamper-proof guarantee. Decoding the signature section tells you nothing useful — but &lt;em&gt;verifying&lt;/em&gt; it tells you whether to trust the token.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Decoding ≠ Verifying.&lt;/strong&gt; Anyone can decode a JWT without a key. Only the party with the correct secret or public key can verify the signature. Always verify on the server before trusting any claims.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The 5 JWT Errors That Waste the Most Time
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Error 1: &lt;code&gt;jwt expired&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Your &lt;code&gt;exp&lt;/code&gt; timestamp is in the past. Easy to diagnose — paste the token in the decoder and check the expiry date.&lt;/p&gt;

&lt;p&gt;If valid tokens appear expired &lt;em&gt;immediately&lt;/em&gt; after creation, you have &lt;strong&gt;clock skew&lt;/strong&gt;. Your issuer and verifier have different system times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add tolerance for clock skew&lt;/span&gt;
&lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;algorithms&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;HS256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;clockTolerance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;  &lt;span class="c1"&gt;// 60 seconds leeway&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;date -u&lt;/code&gt; on both servers. Even 30 seconds difference breaks short-lived tokens.&lt;/p&gt;




&lt;h3&gt;
  
  
  Error 2: &lt;code&gt;invalid signature&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Most common causes (ranked by how often I've seen them in the wild):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Different secret between environments&lt;/strong&gt; — your &lt;code&gt;.env.local&lt;/code&gt; secret doesn't match production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Algorithm mismatch&lt;/strong&gt; — token is HS256, server expects RS256&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base64 encoding issue&lt;/strong&gt; — secret stored as raw string in one place, Base64-encoded in another&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trailing whitespace/newline in env var&lt;/strong&gt; — often from copy-pasting into &lt;code&gt;.env&lt;/code&gt; files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fix: Always whitelist algorithms explicitly:&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;// ✅ Always specify allowed algorithms&lt;/span&gt;
&lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&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;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;algorithms&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;HS256&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="c1"&gt;// ❌ Never do this — vulnerable to algorithm confusion attacks&lt;/span&gt;
&lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&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;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Error 3: &lt;code&gt;jwt malformed&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The token doesn't have exactly 3 dot-separated segments. Common causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forgot to strip the &lt;code&gt;Bearer&lt;/code&gt; prefix before passing to verify&lt;/li&gt;
&lt;li&gt;Token got URL-encoded twice (dots become &lt;code&gt;%2E&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Token was truncated in transit or logging
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ Strip Bearer prefix correctly&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Error 4: Claims mismatch (&lt;code&gt;iss&lt;/code&gt;/&lt;code&gt;aud&lt;/code&gt; invalid)
&lt;/h3&gt;

&lt;p&gt;Token is valid and not expired — but still rejected. Check the &lt;code&gt;iss&lt;/code&gt; and &lt;code&gt;aud&lt;/code&gt; claims in the decoder and compare them character-by-character against your server config.&lt;/p&gt;

&lt;p&gt;Watch for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trailing slash differences (&lt;code&gt;https://api.app.com&lt;/code&gt; vs &lt;code&gt;https://api.app.com/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;HTTP vs HTTPS mismatch&lt;/li&gt;
&lt;li&gt;Port numbers in one config but not the other&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Error 5: &lt;code&gt;alg:none&lt;/code&gt; attack
&lt;/h3&gt;

&lt;p&gt;Not an error you'll encounter — it's an attack you need to block. Some older JWT libraries accept tokens where &lt;code&gt;"alg": "none"&lt;/code&gt; is set in the header. An attacker strips the signature, sets the algorithm to none, and crafts any payload they want.&lt;/p&gt;

&lt;p&gt;The fix is the same as Error 2: always whitelist algorithms. Never trust the algorithm value from the token header itself. Modern libraries like &lt;code&gt;jose&lt;/code&gt; (used in Next.js Edge Runtime) block this by default.&lt;/p&gt;

&lt;p&gt;For Next.js specifically, the article on &lt;a href="https://www.webtoolshub.online/blog/nextjs-edge-runtime-jwt-authentication-jose" rel="noopener noreferrer"&gt;JWT Authentication with JOSE in the Edge Runtime&lt;/a&gt; covers the full setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  The JWT Security Rules That Actually Matter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Never Store JWTs in localStorage
&lt;/h3&gt;

&lt;p&gt;I know every tutorial from 2020 did this. It's still wrong in 2026.&lt;/p&gt;

&lt;p&gt;localStorage is readable by any JavaScript on the page. One XSS vulnerability, one compromised npm package — and every active user's token is gone. I've seen this happen in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The correct pattern:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Access token  → Memory only (React state / context). TTL: 5–15 minutes.
Refresh token → HttpOnly, Secure, SameSite=Lax cookie. Not readable by JS.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HttpOnly cookies literally cannot be accessed by JavaScript. That's the point.&lt;/p&gt;

&lt;p&gt;For a full breakdown of storage options, the &lt;a href="https://www.webtoolshub.online/blog/localstorage-vs-sessionstorage-vs-cookies-guide-2026" rel="noopener noreferrer"&gt;localStorage vs sessionStorage vs Cookies guide&lt;/a&gt; covers every tradeoff in detail.&lt;/p&gt;




&lt;h3&gt;
  
  
  Validate Every Claim on the Server
&lt;/h3&gt;

&lt;p&gt;Verifying the signature is not enough:&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;function&lt;/span&gt; &lt;span class="nf"&gt;verifyToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&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;JWT_SECRET&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;algorithms&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;HS256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.myapp.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;audience&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myapp-frontend&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;as&lt;/span&gt; &lt;span class="nx"&gt;JWTPayload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Explicit expiry check — some libraries skip this by default&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;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Token expired&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;payload&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;Never silently swallow verification failures. Log the exact error message — it tells you precisely what went wrong.&lt;/p&gt;




&lt;h3&gt;
  
  
  Keep Access Token TTL Short
&lt;/h3&gt;

&lt;p&gt;15 minutes. A stolen token that expires in 15 minutes is a minor incident. A stolen token that lasts 7 days is a disaster.&lt;/p&gt;




&lt;h2&gt;
  
  
  HS256 vs RS256 vs ES256 — Quick Decision Guide
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Single service (issues and verifies tokens itself)&lt;/td&gt;
&lt;td&gt;HS256&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple services / microservices&lt;/td&gt;
&lt;td&gt;RS256&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-throughput API, short key preference&lt;/td&gt;
&lt;td&gt;ES256&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Starting a new project right now&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;RS256&lt;/strong&gt; — you'll thank yourself later&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I've migrated projects from HS256 to RS256 mid-flight. It's painful. If you're starting fresh in 2026, go RS256 from day one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verify a JWT Locally with Node.js
&lt;/h2&gt;

&lt;p&gt;When you need this in your terminal during debugging:&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;jwt&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;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;verifyToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&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;JWT_SECRET&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;algorithms&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;HS256&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;✅ Valid:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decoded&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;❌ Failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// "jwt expired" | "invalid signature" | "jwt malformed" | "jwt audience invalid"&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The error message from &lt;code&gt;jwt.verify()&lt;/code&gt; is specific. Use it.&lt;/p&gt;

&lt;p&gt;Need a fresh secret? The &lt;a href="https://www.webtoolshub.online/tools/jwt-secret-key-generator" rel="noopener noreferrer"&gt;JWT Secret Key Generator&lt;/a&gt; creates cryptographically random secrets — minimum 256 bits for HS256.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Note: JWT vs bcrypt
&lt;/h2&gt;

&lt;p&gt;I see this confusion constantly. They solve different problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;bcrypt&lt;/strong&gt; — hashes passwords at registration. You store the hash, never the plain password. At login, compare the submitted password against the stored hash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JWT&lt;/strong&gt; — issued &lt;em&gt;after&lt;/em&gt; bcrypt verifies the password. Represents the authenticated session.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One comes before the other. The &lt;a href="https://www.webtoolshub.online/tools/bcrypt-hash-generator-verifier" rel="noopener noreferrer"&gt;Bcrypt Hash Generator &amp;amp; Verifier&lt;/a&gt; lets you test hashing behavior if you're building the full auth flow.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;JWT = Header (algorithm) + Payload (claims) + Signature (tamper-proof)&lt;/li&gt;
&lt;li&gt;Payload is Base64 &lt;strong&gt;encoded&lt;/strong&gt;, not &lt;strong&gt;encrypted&lt;/strong&gt; — anyone can read it&lt;/li&gt;
&lt;li&gt;Always whitelist algorithms explicitly — never trust the &lt;code&gt;alg&lt;/code&gt; from the token&lt;/li&gt;
&lt;li&gt;Store access tokens in memory, refresh tokens in HttpOnly cookies&lt;/li&gt;
&lt;li&gt;Use RS256 for anything beyond a single-service monolith&lt;/li&gt;
&lt;li&gt;The 5 errors (expired, invalid signature, malformed, claims mismatch, alg:none) cover 95% of JWT debugging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Free tool:&lt;/strong&gt; &lt;a href="https://www.webtoolshub.online/tools/jwt-decoder-verifier" rel="noopener noreferrer"&gt;WebToolsHub JWT Decoder &amp;amp; Verifier&lt;/a&gt; — paste any JWT, get full decoded output in under 5 seconds. Runs in your browser, nothing sent to any server.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.webtoolshub.online/blog/how-to-decode-jwt-token-online-complete-guide-2026" rel="noopener noreferrer"&gt;webtoolshub.online&lt;/a&gt;. Free developer tools including JWT decoder, regex tester, JSON-to-TypeScript converter, and more — no sign-up required.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>10 Regex Patterns Every JavaScript Developer Should Know (2026)</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Sat, 13 Jun 2026 16:30:58 +0000</pubDate>
      <link>https://dev.to/webtoolshub/10-regex-patterns-every-javascript-developer-should-know-2026-4om8</link>
      <guid>https://dev.to/webtoolshub/10-regex-patterns-every-javascript-developer-should-know-2026-4om8</guid>
      <description>&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%2Fgkxk3wyi221qr6ojolob.webp" 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%2Fgkxk3wyi221qr6ojolob.webp" alt="10 Regex Patterns Every JavaScript Developer Should Know (2026)" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
You're halfway through building a signup form. Email field. Phone field. Password field.&lt;/p&gt;

&lt;p&gt;And suddenly you're Googling &lt;em&gt;"email validation regex javascript"&lt;/em&gt; for the 40th time this year — copying a Stack Overflow answer from 2018, crossing your fingers, and moving on.&lt;/p&gt;

&lt;p&gt;I've done this. On production projects. That's embarrassing to admit, but it's also why I finally built a proper reference — one I actually understand, not just copy-paste blindly.&lt;/p&gt;

&lt;p&gt;These are the &lt;strong&gt;10 regex patterns&lt;/strong&gt; I reach for constantly in JavaScript projects. Each one is copy-paste ready, explained properly, and tested against real edge cases.&lt;/p&gt;


&lt;h2&gt;
  
  
  What You'll Learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;10 production-ready regex patterns with copy-paste JS code&lt;/li&gt;
&lt;li&gt;What each pattern actually does — no cryptic symbol blindness&lt;/li&gt;
&lt;li&gt;Edge cases that will bite you if you skip them&lt;/li&gt;
&lt;li&gt;Common mistakes that ship to production every single day&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Quick Method Reference
&lt;/h2&gt;

&lt;p&gt;Before the patterns — the three methods you'll use 90% of the time:&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="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;// → true/false. Use for validation.&lt;/span&gt;
&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/pattern/g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;// → array of matches. Use for extraction.&lt;/span&gt;
&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/pattern/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// → new string. Use for sanitization.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's genuinely all you need. Let's get into the patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Email Validation
&lt;/h2&gt;

&lt;p&gt;This is the one everyone needs and everyone gets slightly wrong.&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;emailRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[^\s&lt;/span&gt;&lt;span class="sr"&gt;@&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+@&lt;/span&gt;&lt;span class="se"&gt;[^\s&lt;/span&gt;&lt;span class="sr"&gt;@&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.[^\s&lt;/span&gt;&lt;span class="sr"&gt;@&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isValidEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;emailRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&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="nf"&gt;isValidEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;    &lt;span class="c1"&gt;// ✅ true&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="nf"&gt;isValidEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user+tag@company.co&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// ✅ true — plus sign works&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="nf"&gt;isValidEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notanemail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;           &lt;span class="c1"&gt;// ❌ false&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="nf"&gt;isValidEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;missing@tld&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;          &lt;span class="c1"&gt;// ❌ false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What &lt;code&gt;[^\s@]+&lt;/code&gt; does:&lt;/strong&gt; Matches one or more characters that are NOT a space or &lt;code&gt;@&lt;/code&gt;. Simple, readable, and handles edge cases like plus-sign aliases (&lt;code&gt;user+filter@gmail.com&lt;/code&gt;) and long TLDs like &lt;code&gt;.photography&lt;/code&gt; — things that trip up overcomplicated RFC-5322 patterns.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important:&lt;/strong&gt; Regex validates &lt;em&gt;format&lt;/em&gt;, not deliverability. It can't tell you if the mailbox actually exists. For that, use a verification API or just send a confirmation email.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Password Strength (with Lookaheads)
&lt;/h2&gt;

&lt;p&gt;Most auth systems need: 8+ characters, one uppercase, one lowercase, one digit, one special character. Here's the pattern using &lt;strong&gt;lookaheads&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;strongPasswordRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(?=&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-z&lt;/span&gt;&lt;span class="se"&gt;])(?=&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;A-Z&lt;/span&gt;&lt;span class="se"&gt;])(?=&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;\d)(?=&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;!@#$%^&amp;amp;*()_+&lt;/span&gt;&lt;span class="se"&gt;\-&lt;/span&gt;&lt;span class="sr"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\[\]&lt;/span&gt;&lt;span class="sr"&gt;{}|;:,.&amp;lt;&amp;gt;?&lt;/span&gt;&lt;span class="se"&gt;])&lt;/span&gt;&lt;span class="sr"&gt;.&lt;/span&gt;&lt;span class="se"&gt;{8,}&lt;/span&gt;&lt;span class="sr"&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;mediumPasswordRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(?=&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;A-Z&lt;/span&gt;&lt;span class="se"&gt;])(?=&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;\d)&lt;/span&gt;&lt;span class="sr"&gt;.&lt;/span&gt;&lt;span class="se"&gt;{8,}&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkPasswordStrength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&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;strongPasswordRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strong&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;mediumPasswordRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;weak&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="nf"&gt;checkPasswordStrength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Passw0rd!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// strong&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="nf"&gt;checkPasswordStrength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Password1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// medium&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="nf"&gt;checkPasswordStrength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// weak&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How lookaheads work:&lt;/strong&gt; &lt;code&gt;(?=.*[A-Z])&lt;/code&gt; says "look ahead and confirm at least one uppercase letter exists somewhere in the string" — without consuming characters. Each &lt;code&gt;(?=...)&lt;/code&gt; is a separate requirement. The final &lt;code&gt;.{8,}&lt;/code&gt; enforces minimum length.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;bcrypt gotcha:&lt;/strong&gt; bcrypt silently truncates passwords at 72 bytes. If users set 100-character passphrases, only the first 72 characters are actually hashed. Worth mentioning in your security docs.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. URL Validation
&lt;/h2&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;urlRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^https&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\/\/(&lt;/span&gt;&lt;span class="sr"&gt;www&lt;/span&gt;&lt;span class="se"&gt;\.)?[&lt;/span&gt;&lt;span class="sr"&gt;-a-zA-Z0-9@:%._+~#=&lt;/span&gt;&lt;span class="se"&gt;]{1,256}\.[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9()&lt;/span&gt;&lt;span class="se"&gt;]{1,6}\b([&lt;/span&gt;&lt;span class="sr"&gt;-a-zA-Z0-9()@:%_+.~#?&amp;amp;&lt;/span&gt;&lt;span class="se"&gt;/&lt;/span&gt;&lt;span class="sr"&gt;=&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&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;urlRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://webtoolshub.online&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;          &lt;span class="c1"&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;urlRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://sub.domain.co.uk/path?q=1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&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;urlRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ftp://not-http.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;                   &lt;span class="c1"&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;urlRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;just-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;                            &lt;span class="c1"&gt;// ❌&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Honest take:&lt;/strong&gt; For complex URL parsing in production, use the built-in &lt;code&gt;URL&lt;/code&gt; constructor — &lt;code&gt;new URL(str)&lt;/code&gt; throws if invalid, easier to handle with try/catch. The regex is perfect for quick form validation.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Phone Number (International)
&lt;/h2&gt;

&lt;p&gt;Phone numbers are where regex ambitions go to die. No single regex perfectly handles every international format. Here's what I actually 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="c1"&gt;// Flexible — strip formatting first, then validate digit count&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isValidPhone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;phone&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;digitsOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\s\-&lt;/span&gt;&lt;span class="sr"&gt;().+&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\d{7,15}&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digitsOnly&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="nf"&gt;isValidPhone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+92 300 1234567&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&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="nf"&gt;isValidPhone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(555) 867-5309&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&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="nf"&gt;isValidPhone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;              &lt;span class="c1"&gt;// ❌&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real talk:&lt;/strong&gt; Strip non-digits first, count the digits, move on. Users type phone numbers in wildly different formats. This handles 95% of real-world input better than any strict pattern.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. URL Slug (SEO-Friendly)
&lt;/h2&gt;

&lt;p&gt;Essential for any CMS, blog, or content platform. A slug: lowercase letters, numbers, hyphens only.&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;slugRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-z0-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-z0-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;*$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;slugify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^\w\s&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// remove special chars&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\s&lt;/span&gt;&lt;span class="sr"&gt;_-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// spaces/underscores → hyphens&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^-+|-+$/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// trim leading/trailing hyphens&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="nf"&gt;slugify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My Blog Post Title!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;       &lt;span class="c1"&gt;// "my-blog-post-title"&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="nf"&gt;slugify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  TypeScript &amp;amp; Next.js  &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// "typescript-nextjs"&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;slugRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;valid-slug-123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;      &lt;span class="c1"&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;slugRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid Slug!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;       &lt;span class="c1"&gt;// ❌&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;slugify&lt;/code&gt; function is more useful than just the validation regex — I use it everywhere in Next.js projects when auto-generating routes from titles.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Hex Color Code
&lt;/h2&gt;

&lt;p&gt;For color pickers, CSS parsers, and theme generators. Handles 3-digit and 6-digit formats:&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;hexColorRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^#&lt;/span&gt;&lt;span class="se"&gt;([&lt;/span&gt;&lt;span class="sr"&gt;A-Fa-f0-9&lt;/span&gt;&lt;span class="se"&gt;]{6}&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;A-Fa-f0-9&lt;/span&gt;&lt;span class="se"&gt;]{3})&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// With alpha channel (8-digit and 4-digit)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hexWithAlphaRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^#&lt;/span&gt;&lt;span class="se"&gt;([&lt;/span&gt;&lt;span class="sr"&gt;A-Fa-f0-9&lt;/span&gt;&lt;span class="se"&gt;]{8}&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;A-Fa-f0-9&lt;/span&gt;&lt;span class="se"&gt;]{6}&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;A-Fa-f0-9&lt;/span&gt;&lt;span class="se"&gt;]{4}&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;A-Fa-f0-9&lt;/span&gt;&lt;span class="se"&gt;]{3})&lt;/span&gt;&lt;span class="sr"&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;hexColorRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;       &lt;span class="c1"&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;hexColorRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#FF5733&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;    &lt;span class="c1"&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;hexColorRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FF5733&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;     &lt;span class="c1"&gt;// ❌ — missing #&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;hexColorRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#GGGGGG&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;    &lt;span class="c1"&gt;// ❌ — G isn't hex&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Date Format (ISO: YYYY-MM-DD)
&lt;/h2&gt;

&lt;p&gt;What every API expects, what databases prefer. This validates format — not date logic:&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;isoDateRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\d{4}&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;0&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;1-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;|1&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-2&lt;/span&gt;&lt;span class="se"&gt;])&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;0&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;1-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;12&lt;/span&gt;&lt;span class="se"&gt;]\d&lt;/span&gt;&lt;span class="sr"&gt;|3&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;01&lt;/span&gt;&lt;span class="se"&gt;])&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// For logic validation, combine with Date constructor&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isValidDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isoDateRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&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="nf"&gt;isValidDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-06-13&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&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="nf"&gt;isValidDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-02-30&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// ❌ — Feb 30 caught by Date constructor&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="nf"&gt;isValidDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-13-01&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// ❌ — month 13 caught by regex&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Always use both:&lt;/strong&gt; Regex catches format errors; &lt;code&gt;new Date()&lt;/code&gt; catches impossible dates like Feb 30.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  8. Username Validation
&lt;/h2&gt;

&lt;p&gt;Standard rules: 3-20 characters, letters, numbers, underscores, hyphens — no spaces.&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;usernameRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9_-&lt;/span&gt;&lt;span class="se"&gt;]{3,20}&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Stricter — must start with a letter&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;strictUsernameRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z&lt;/span&gt;&lt;span class="se"&gt;][&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9_-&lt;/span&gt;&lt;span class="se"&gt;]{2,19}&lt;/span&gt;&lt;span class="sr"&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;usernameRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;muhammad_awais&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&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;usernameRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dev-42&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;         &lt;span class="c1"&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;usernameRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;             &lt;span class="c1"&gt;// ❌ — too short&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;usernameRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;has spaces&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;     &lt;span class="c1"&gt;// ❌&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adjust &lt;code&gt;{3,20}&lt;/code&gt; to your requirements. The strict version prevents usernames like &lt;code&gt;_admin&lt;/code&gt; — cleaner in URLs and @mentions.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. IPv4 Address (Strict)
&lt;/h2&gt;

&lt;p&gt;Basic patterns let &lt;code&gt;999.0.0.1&lt;/code&gt; through. This one properly validates each octet (0-255):&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;ipv4Regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;25&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-5&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;|2&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-4&lt;/span&gt;&lt;span class="se"&gt;]\d&lt;/span&gt;&lt;span class="sr"&gt;|1&lt;/span&gt;&lt;span class="se"&gt;\d{2}&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;1-9&lt;/span&gt;&lt;span class="se"&gt;]\d&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;\d)\.(&lt;/span&gt;&lt;span class="sr"&gt;25&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-5&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;|2&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-4&lt;/span&gt;&lt;span class="se"&gt;]\d&lt;/span&gt;&lt;span class="sr"&gt;|1&lt;/span&gt;&lt;span class="se"&gt;\d{2}&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;1-9&lt;/span&gt;&lt;span class="se"&gt;]\d&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;\d)\.(&lt;/span&gt;&lt;span class="sr"&gt;25&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-5&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;|2&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-4&lt;/span&gt;&lt;span class="se"&gt;]\d&lt;/span&gt;&lt;span class="sr"&gt;|1&lt;/span&gt;&lt;span class="se"&gt;\d{2}&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;1-9&lt;/span&gt;&lt;span class="se"&gt;]\d&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;\d)\.(&lt;/span&gt;&lt;span class="sr"&gt;25&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-5&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;|2&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-4&lt;/span&gt;&lt;span class="se"&gt;]\d&lt;/span&gt;&lt;span class="sr"&gt;|1&lt;/span&gt;&lt;span class="se"&gt;\d{2}&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;1-9&lt;/span&gt;&lt;span class="se"&gt;]\d&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;\d)&lt;/span&gt;&lt;span class="sr"&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;ipv4Regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;192.168.1.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&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;ipv4Regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;255.255.255.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&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;ipv4Regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;999.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;     &lt;span class="c1"&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;ipv4Regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;192.168.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;     &lt;span class="c1"&gt;// ❌&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How the octet math works:&lt;/strong&gt; &lt;code&gt;25[0-5]&lt;/code&gt; → 250-255 | &lt;code&gt;2[0-4]\d&lt;/code&gt; → 200-249 | &lt;code&gt;1\d{2}&lt;/code&gt; → 100-199 | &lt;code&gt;[1-9]\d&lt;/code&gt; → 10-99 | &lt;code&gt;\d&lt;/code&gt; → 0-9. Always use the strict version — bad IPs cause cryptic downstream errors.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Credit Card Format
&lt;/h2&gt;

&lt;p&gt;Format-only validation. For real validation, always combine with the Luhn algorithm:&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;creditCardRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\d{13,19}&lt;/span&gt;&lt;span class="sr"&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;cardTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;visa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="sr"&gt;/^4&lt;/span&gt;&lt;span class="se"&gt;\d{12}(?:\d{3})?&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;mastercard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^5&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;1-5&lt;/span&gt;&lt;span class="se"&gt;]\d{14}&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;amex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="sr"&gt;/^3&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;47&lt;/span&gt;&lt;span class="se"&gt;]\d{13}&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;discover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="sr"&gt;/^6&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;011|5&lt;/span&gt;&lt;span class="se"&gt;\d{2})\d{12}&lt;/span&gt;&lt;span class="sr"&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;function&lt;/span&gt; &lt;span class="nf"&gt;identifyCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&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;stripped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\s\-]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;creditCardRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stripped&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invalid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cardTypes&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;regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stripped&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;type&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unknown&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="nf"&gt;identifyCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4111 1111 1111 1111&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// visa&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="nf"&gt;identifyCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5500 0000 0000 0004&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// mastercard&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="nf"&gt;identifyCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1234 5678&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;           &lt;span class="c1"&gt;// invalid&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Production rule:&lt;/strong&gt; Use a payment processor (Stripe, etc.) for actual card validation. Never store raw card numbers.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Common Mistakes That Ship to Production
&lt;/h2&gt;

&lt;p&gt;I've made all of these. Some of them twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Forgetting &lt;code&gt;^&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; anchors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Without anchors, your pattern matches &lt;em&gt;anywhere&lt;/em&gt; in the string.&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;// ❌ Wrong — matches "I have 1234 in the middle"&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;badPin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\d{4}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Correct — only matches exactly 4 digits&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;goodPin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\d{4}&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Not escaping the dot&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In regex, &lt;code&gt;.&lt;/code&gt; means "any character". So &lt;code&gt;example.com&lt;/code&gt; as a pattern also matches &lt;code&gt;exampleXcom&lt;/code&gt;. Always escape: &lt;code&gt;example\.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Catastrophic backtracking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nested quantifiers like &lt;code&gt;/(a+)+/&lt;/code&gt; can hang your regex engine on long strings (ReDoS attack). Avoid nesting &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;*&lt;/code&gt; inside groups that already have &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Missing the &lt;code&gt;i&lt;/code&gt; flag for case-insensitive matching&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Email addresses are case-insensitive. &lt;code&gt;User@Example.COM&lt;/code&gt; is the same mailbox as &lt;code&gt;user@example.com&lt;/code&gt;. Use &lt;code&gt;/pattern/i&lt;/code&gt; or normalize with &lt;code&gt;.toLowerCase()&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Using regex to parse HTML&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don't. Use &lt;code&gt;DOMParser&lt;/code&gt; in the browser or &lt;code&gt;cheerio&lt;/code&gt; in Node. Regex and HTML is a well-documented disaster.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Reference Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^[^\s@]+@[^\s@]+\.[^\s@]+$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;i&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strong Password&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&amp;amp;*]).{8,}$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^https?:\/\/(www\.)?[-\w@:%._+~#=]{1,256}\.[a-zA-Z]{1,6}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;i&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phone&lt;/td&gt;
&lt;td&gt;Strip non-digits → &lt;code&gt;^\d{7,15}$&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;URL Slug&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^[a-z0-9]+(?:-[a-z0-9]+)*$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hex Color&lt;/td&gt;
&lt;td&gt;`^#([A-Fa-f0-9]{6}\&lt;/td&gt;
&lt;td&gt;[A-Fa-f0-9]{3})$`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ISO Date&lt;/td&gt;
&lt;td&gt;`^\d{4}-(0[1-9]\&lt;/td&gt;
&lt;td&gt;1[0-2])-(0[1-9]\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Username&lt;/td&gt;
&lt;td&gt;{% raw %}&lt;code&gt;^[a-zA-Z0-9_-]{3,20}$&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPv4&lt;/td&gt;
&lt;td&gt;`^(25[0-5]\&lt;/td&gt;
&lt;td&gt;2[0-4]\d\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credit Card&lt;/td&gt;
&lt;td&gt;Strip spaces → {% raw %}&lt;code&gt;^\d{13,19}$&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Test These Live
&lt;/h2&gt;

&lt;p&gt;Before you ship any pattern, spend 2 minutes testing it. I use &lt;a href="https://www.webtoolshub.online/tools/regex-tester-debugger" rel="noopener noreferrer"&gt;WebToolsHub's free Regex Tester&lt;/a&gt; — paste the pattern, add test strings including intentionally bad ones, see matches highlighted in real time. Everything runs in your browser, nothing gets sent to a server.&lt;/p&gt;

&lt;p&gt;This two-minute habit has saved me from broken validation in production more times than I want to count.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want to Go Deeper?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.webtoolshub.online/blog/mastering-regular-expressions-regex-javascript-guide" rel="noopener noreferrer"&gt;Complete Regex Guide for JavaScript&lt;/a&gt; — capture groups, lookaheads, flags, all of it&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.webtoolshub.online/blog/nextjs-14-server-actions-security-guide" rel="noopener noreferrer"&gt;Next.js Server Actions Security Guide&lt;/a&gt; — where these patterns get used in real auth flows&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions" rel="noopener noreferrer"&gt;MDN Regular Expressions&lt;/a&gt; — the authoritative reference&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;All tools on WebToolsHub are 100% client-side — no data is sent to any server. Your patterns and test strings stay in your browser.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>regex</category>
    </item>
    <item>
      <title>Stop Guessing EM Values — Here's the Formula Every CSS Dev Needs (+ Free Tool)</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Fri, 12 Jun 2026 07:28:21 +0000</pubDate>
      <link>https://dev.to/webtoolshub/stop-guessing-em-values-heres-the-formula-every-css-dev-needs-free-tool-3clc</link>
      <guid>https://dev.to/webtoolshub/stop-guessing-em-values-heres-the-formula-every-css-dev-needs-free-tool-3clc</guid>
      <description>&lt;p&gt;You've been there. Figma hands you &lt;code&gt;24px&lt;/code&gt;. Your component has a parent with &lt;code&gt;font-size: 20px&lt;/code&gt;. You open some random px-to-em converter, type 24, and it spits out &lt;code&gt;1.5em&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Wrong. That's calculated against 16px, not your actual parent. You paste it in, something looks slightly off, you squint at it for 10 minutes, and eventually pull up DevTools to figure out what happened.&lt;/p&gt;

&lt;p&gt;This post explains why em is context-dependent, how the formula actually works, and walks through the tool I built to fix this exact frustration.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Formula (And Why It Trips People Up)
&lt;/h2&gt;

&lt;p&gt;The math is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;em  = px ÷ parent font-size (px)
px  = em × parent font-size (px)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;24px&lt;/code&gt; with a &lt;code&gt;16px&lt;/code&gt; parent = &lt;code&gt;1.5em&lt;/code&gt;. Clean.&lt;/p&gt;

&lt;p&gt;But here's what most tutorials gloss over: &lt;strong&gt;em isn't relative to the browser default or the document root — it's relative to the &lt;em&gt;computed&lt;/em&gt; font-size of the &lt;em&gt;parent element&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That sounds obvious. But in practice?&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="nt"&gt;html&lt;/span&gt;       &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.25em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c"&gt;/* computed: 20px */&lt;/span&gt;
&lt;span class="nc"&gt;.card-body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.9em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c"&gt;/* computed: 18px (20 × 0.9) */&lt;/span&gt;
&lt;span class="nc"&gt;.card-body&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.875em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;/* computed: 15.75px (18 × 0.875) */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each level multiplies against its parent's &lt;strong&gt;computed&lt;/strong&gt; size. This is called &lt;strong&gt;EM compounding&lt;/strong&gt;, and it's why you sometimes end up with 11px text when you thought you set &lt;code&gt;0.875em&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The fix is to always check the actual computed font-size in DevTools, not the declared value — and use &lt;em&gt;that&lt;/em&gt; as your parent reference when converting.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Most PX→EM Tools Get Wrong
&lt;/h2&gt;

&lt;p&gt;I tested every tool that shows up on Google for "px to em converter":&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Live Formula?&lt;/th&gt;
&lt;th&gt;Configurable Parent?&lt;/th&gt;
&lt;th&gt;Bulk Convert?&lt;/th&gt;
&lt;th&gt;Tailwind Output?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;w3schools reference&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nekocalc.com&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pixelsconverter.com&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;giantfocal.com&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WebToolsHub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The live formula display is the thing I care about most. When you see &lt;code&gt;24px ÷ 16px (parent) = 1.5em&lt;/code&gt; right there on screen, you &lt;em&gt;understand&lt;/em&gt; what's happening — you're not treating the tool as a black box.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tool: What It Actually Does
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://www.webtoolshub.online/tools/px-to-em-converter" rel="noopener noreferrer"&gt;this PX to EM converter&lt;/a&gt; with the workflow of an actual frontend developer in mind. Here's what makes it different:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Bidirectional Conversion with Swap
&lt;/h3&gt;

&lt;p&gt;Toggle between &lt;strong&gt;PX → EM&lt;/strong&gt; and &lt;strong&gt;EM → PX&lt;/strong&gt;. The swap button (⇄) flips direction &lt;em&gt;and&lt;/em&gt; moves your current result into the input — useful for chain conversions like "I have 1.5em, what's that in px at 20px parent, then convert &lt;em&gt;that&lt;/em&gt; back to em at 14px parent."&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Live Formula Bar
&lt;/h3&gt;

&lt;p&gt;As you type, you see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;24px ÷ 16px (parent) = 1.5em
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No black box. You see the math. You catch mistakes immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Configurable Parent Font Size
&lt;/h3&gt;

&lt;p&gt;This is the feature that makes the tool actually correct. Default is 16px, but you can set it to anything. Change it to 20px and your &lt;code&gt;24px&lt;/code&gt; becomes &lt;code&gt;1.2em&lt;/code&gt; — which is the right answer when your parent is &lt;code&gt;20px&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every section (main converter, bulk rows, reference table) reacts to this setting instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Quick-Copy Property Cards
&lt;/h3&gt;

&lt;p&gt;Four cards appear after conversion:&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="nt"&gt;font-size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="nt"&gt;em&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   &lt;span class="c"&gt;/* click to copy */&lt;/span&gt;
&lt;span class="nt"&gt;margin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="nt"&gt;em&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;      &lt;span class="c"&gt;/* click to copy */&lt;/span&gt;
&lt;span class="nt"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="nt"&gt;em&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;     &lt;span class="c"&gt;/* click to copy */&lt;/span&gt;
&lt;span class="nt"&gt;gap&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="nt"&gt;em&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;         &lt;span class="c"&gt;/* click to copy */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The card flashes green on copy. Small thing, but it's faster than manually typing the property name every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. CSS Snippet + Tailwind Arbitrary Value
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;font-size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="nt"&gt;em&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* 24px */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;text-[1.5em]   ← Tailwind arbitrary value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The comment preserving the original px value is intentional — keep it in your CSS. Six months later when you're debugging, you'll thank yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Bulk Converter
&lt;/h3&gt;

&lt;p&gt;For design systems, I usually need to convert an entire type scale at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input:  16, 20, 24, 32, 48px
Output: 1em, 1.25em, 1.5em, 2em, 3em  (at 16px parent)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add rows, edit values, hit "Copy All." If you're working with a custom parent, change the parent field and every row updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. 1–100px Reference Table (3 paginated ranges)
&lt;/h3&gt;

&lt;p&gt;Paginated into 1–20px, 21–50px, 51–100px so the page doesn't turn into a massive scroll. Every row has a copy icon. The whole table recalculates when you change the parent font size.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. EM vs REM vs PX Explainer (Collapsible)
&lt;/h3&gt;

&lt;p&gt;For those moments when you're onboarding a junior dev or just can't remember which unit anchors to root:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Relative To&lt;/th&gt;
&lt;th&gt;Compounds?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;px&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nothing (absolute)&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;em&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Parent element font-size&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rem&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Root &lt;code&gt;html&lt;/code&gt; font-size&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  em vs rem: My Practical Rule
&lt;/h2&gt;

&lt;p&gt;I've settled on this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;rem&lt;/code&gt; for type scale and layout. &lt;code&gt;em&lt;/code&gt; for component internals.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A button's &lt;code&gt;font-size&lt;/code&gt; is &lt;code&gt;0.875rem&lt;/code&gt; (anchored to root, predictable). But its &lt;code&gt;padding&lt;/code&gt; is &lt;code&gt;0.5em 1em&lt;/code&gt; — so if you want a "large button" you just change &lt;code&gt;font-size: 1.1rem&lt;/code&gt; and the padding scales automatically with it.&lt;/p&gt;

&lt;p&gt;That's the real power of &lt;code&gt;em&lt;/code&gt; — not typography, but proportional spacing &lt;em&gt;within&lt;/em&gt; a component.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes (Real Ones From Real Projects)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mistake 1: Using default 16px when your parent isn't 16px&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every time you open a converter and just type a number without checking what the actual parent font size is, you might be wrong. 16px is a default, not a constant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 2: Using em for font-size in nested components&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three levels of &lt;code&gt;1.2em&lt;/code&gt; = &lt;code&gt;1.728em&lt;/code&gt; effective. This is almost never what you want. Use rem for font sizes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 3: Deleting the px comment from your CSS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;font-size: 1.5em&lt;/code&gt; is meaningless without knowing it came from &lt;code&gt;24px&lt;/code&gt; at &lt;code&gt;16px&lt;/code&gt; parent. Keep the comment. Future you will not remember.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 4: The &lt;code&gt;62.5%&lt;/code&gt; trick messing up your calculations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some codebases set &lt;code&gt;html { font-size: 62.5%; }&lt;/code&gt; to make 1rem = 10px. If you're working in one of those, your em calculations are also off because parent sizes are now computed differently down the tree.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;→ &lt;strong&gt;&lt;a href="https://www.webtoolshub.online/tools/px-to-em-converter" rel="noopener noreferrer"&gt;PX to EM Converter — WebToolsHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;100% client-side. No account. No data sent to a server. Works offline once loaded.&lt;/p&gt;

&lt;p&gt;If you also work with &lt;code&gt;rem&lt;/code&gt;, I built a &lt;a href="https://www.webtoolshub.online/tools/px-to-rem-converter" rel="noopener noreferrer"&gt;PX to REM Converter&lt;/a&gt; with the same interface — same live formula, same bulk converter, but anchored to root instead of parent.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Reference Table (16px parent)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;px&lt;/th&gt;
&lt;th&gt;em&lt;/th&gt;
&lt;th&gt;px&lt;/th&gt;
&lt;th&gt;em&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10px&lt;/td&gt;
&lt;td&gt;0.625em&lt;/td&gt;
&lt;td&gt;24px&lt;/td&gt;
&lt;td&gt;1.5em&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12px&lt;/td&gt;
&lt;td&gt;0.75em&lt;/td&gt;
&lt;td&gt;32px&lt;/td&gt;
&lt;td&gt;2em&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14px&lt;/td&gt;
&lt;td&gt;0.875em&lt;/td&gt;
&lt;td&gt;40px&lt;/td&gt;
&lt;td&gt;2.5em&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16px&lt;/td&gt;
&lt;td&gt;1em&lt;/td&gt;
&lt;td&gt;48px&lt;/td&gt;
&lt;td&gt;3em&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18px&lt;/td&gt;
&lt;td&gt;1.125em&lt;/td&gt;
&lt;td&gt;64px&lt;/td&gt;
&lt;td&gt;4em&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20px&lt;/td&gt;
&lt;td&gt;1.25em&lt;/td&gt;
&lt;td&gt;80px&lt;/td&gt;
&lt;td&gt;5em&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;What's your rule of thumb for when to use &lt;code&gt;em&lt;/code&gt; vs &lt;code&gt;rem&lt;/code&gt;? Drop it in the comments — I'm curious how others think about this.&lt;/p&gt;

&lt;h1&gt;
  
  
  css #webdev #frontend #tools
&lt;/h1&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>tools</category>
    </item>
    <item>
      <title>Stop Doing px rem Math in Your Head (Here's Why It's Killing Your Flow)</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Fri, 12 Jun 2026 04:59:21 +0000</pubDate>
      <link>https://dev.to/webtoolshub/stop-doing-px-rem-math-in-your-head-heres-why-its-killing-your-flow-4l0a</link>
      <guid>https://dev.to/webtoolshub/stop-doing-px-rem-math-in-your-head-heres-why-its-killing-your-flow-4l0a</guid>
      <description>&lt;p&gt;You're 40 minutes deep into a component. Figma says &lt;code&gt;font-size: 24px&lt;/code&gt;. You open a calculator, type &lt;code&gt;24 / 16&lt;/code&gt;, get &lt;code&gt;1.5&lt;/code&gt;, switch back to VS Code, type &lt;code&gt;1.5rem&lt;/code&gt;, close the calculator.&lt;/p&gt;

&lt;p&gt;Three minutes later you need &lt;code&gt;36px&lt;/code&gt;. Calculator again. &lt;code&gt;36 / 16&lt;/code&gt;... is that &lt;code&gt;2.25&lt;/code&gt;? Let me double check...&lt;/p&gt;

&lt;p&gt;Sound familiar? I've been there more times than I can count. And honestly — it's one of those tiny frictions that doesn't feel like a big deal until you realize you've done it 20 times in a single session.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why We're Still Doing This Manually
&lt;/h2&gt;

&lt;p&gt;The formula is stupid simple:&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="nt"&gt;rem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;÷&lt;/span&gt; &lt;span class="nt"&gt;base&lt;/span&gt; &lt;span class="nt"&gt;font&lt;/span&gt; &lt;span class="nt"&gt;size&lt;/span&gt;
&lt;span class="nt"&gt;px&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;rem&lt;/span&gt; &lt;span class="err"&gt;×&lt;/span&gt; &lt;span class="nt"&gt;base&lt;/span&gt; &lt;span class="nt"&gt;font&lt;/span&gt; &lt;span class="nt"&gt;size&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a &lt;code&gt;16px&lt;/code&gt; base (browser default):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;24px ÷ 16 = 1.5rem   ✓
36px ÷ 16 = 2.25rem  ✓
14px ÷ 16 = 0.875rem ✓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So yeah, the math isn't hard. The problem is &lt;strong&gt;context switching&lt;/strong&gt;. Every time you leave your editor to calculate something, you're paying a mental overhead cost. Stack that 15–20 times per session and you've lost a solid chunk of deep work time.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Quick Reference You Actually Need
&lt;/h2&gt;

&lt;p&gt;Here are the values I reach for constantly — with a standard &lt;code&gt;16px&lt;/code&gt; base:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;px&lt;/th&gt;
&lt;th&gt;rem&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10px&lt;/td&gt;
&lt;td&gt;0.625rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12px&lt;/td&gt;
&lt;td&gt;0.75rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14px&lt;/td&gt;
&lt;td&gt;0.875rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16px&lt;/td&gt;
&lt;td&gt;1rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18px&lt;/td&gt;
&lt;td&gt;1.125rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20px&lt;/td&gt;
&lt;td&gt;1.25rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;24px&lt;/td&gt;
&lt;td&gt;1.5rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;28px&lt;/td&gt;
&lt;td&gt;1.75rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;32px&lt;/td&gt;
&lt;td&gt;2rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;36px&lt;/td&gt;
&lt;td&gt;2.25rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;40px&lt;/td&gt;
&lt;td&gt;2.5rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;48px&lt;/td&gt;
&lt;td&gt;3rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;56px&lt;/td&gt;
&lt;td&gt;3.5rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;64px&lt;/td&gt;
&lt;td&gt;4rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;80px&lt;/td&gt;
&lt;td&gt;5rem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;96px&lt;/td&gt;
&lt;td&gt;6rem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Bookmark this section. Seriously.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wait — Why rem At All?
&lt;/h2&gt;

&lt;p&gt;If you're newer to CSS, you might be wondering why we bother with &lt;code&gt;rem&lt;/code&gt; in the first place. Pixels work fine, right?&lt;/p&gt;

&lt;p&gt;Here's the thing: &lt;code&gt;px&lt;/code&gt; is an absolute unit. When you write &lt;code&gt;font-size: 16px&lt;/code&gt;, that's &lt;em&gt;always&lt;/em&gt; 16 pixels, regardless of what the user has set in their browser preferences.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rem&lt;/code&gt; is relative to the root &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element's font size — which browsers default to &lt;code&gt;16px&lt;/code&gt;, but users can change. That one difference matters a lot for accessibility.&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;/* User sets browser font to "Large" (say, 20px) */&lt;/span&gt;

&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c"&gt;/* still renders at 16px — ignores user */&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c"&gt;/* renders at 20px — respects user */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WCAG 2.2 criterion 1.4.4 (Resize Text) requires that users can resize text up to 200% without breaking layout or losing content. &lt;code&gt;rem&lt;/code&gt; handles this automatically. &lt;code&gt;px&lt;/code&gt; doesn't.&lt;/p&gt;

&lt;p&gt;Beyond accessibility, &lt;code&gt;rem&lt;/code&gt; makes your spacing system predictable. Change the root font size once — everything scales proportionally.&lt;/p&gt;




&lt;h2&gt;
  
  
  The &lt;code&gt;html { font-size: 62.5% }&lt;/code&gt; Trick (And Why It's Outdated)
&lt;/h2&gt;

&lt;p&gt;You've probably seen this pattern in older codebases:&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="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;62.5%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* Makes 1rem = 10px */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3.6rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c"&gt;/* = 36px */&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.6rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c"&gt;/* = 16px */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The appeal: round numbers. &lt;code&gt;36px = 3.6rem&lt;/code&gt; feels cleaner than &lt;code&gt;2.25rem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The problem: setting &lt;code&gt;font-size: 62.5%&lt;/code&gt; on &lt;code&gt;html&lt;/code&gt; overrides the user's browser preference &lt;em&gt;before&lt;/em&gt; anything can respond to it. You're essentially opting out of accessibility at the root level.&lt;/p&gt;

&lt;p&gt;Modern best practice is to leave the &lt;code&gt;html&lt;/code&gt; font size alone (or use &lt;code&gt;100%&lt;/code&gt;) and let &lt;code&gt;1rem = user's preference&lt;/code&gt;. Then use a converter tool to do the math — not a base-size hack.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dealing With a Non-Standard Base in Your Project
&lt;/h2&gt;

&lt;p&gt;Not every project uses &lt;code&gt;16px&lt;/code&gt;. You might inherit a codebase with:&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="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;/* or */&lt;/span&gt;
&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18px&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;In these cases the standard conversion tables are wrong. &lt;code&gt;24px&lt;/code&gt; is NOT &lt;code&gt;1.5rem&lt;/code&gt; if your base is &lt;code&gt;10px&lt;/code&gt; — it's &lt;code&gt;2.4rem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is one reason I always use a proper px → rem converter with a configurable base rather than relying on memory or hardcoded tables. When I'm working on a project with a custom root font size, I just update the base field and every value recalculates correctly.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://www.webtoolshub.online/tools/px-to-rem-converter" rel="noopener noreferrer"&gt;&lt;strong&gt;Free PX to REM Converter — bidirectional, custom base, bulk conversion&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  My Actual Workflow: Converting a Full Type Scale
&lt;/h2&gt;

&lt;p&gt;When I'm starting a new design system or setting up typography tokens, I use the bulk converter instead of doing values one by one.&lt;/p&gt;

&lt;p&gt;Say your designer gave you this type scale in Figma (all in pixels):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;12 / 14 / 16 / 18 / 20 / 24 / 30 / 36 / 48 / 60 / 72
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Throw all 11 values into the bulk converter, hit "Copy All", and you get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;12px = 0.75rem
14px = 0.875rem
16px = 1rem
18px = 1.125rem
20px = 1.25rem
24px = 1.5rem
30px = 1.875rem
36px = 2.25rem
48px = 3rem
60px = 3.75rem
72px = 4.5rem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste directly into your CSS custom properties or Tailwind config. Done in 30 seconds instead of 5 minutes.&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="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--text-xs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="m"&gt;0.75rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c"&gt;/* 12px */&lt;/span&gt;
  &lt;span class="py"&gt;--text-sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="m"&gt;0.875rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;/* 14px */&lt;/span&gt;
  &lt;span class="py"&gt;--text-base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c"&gt;/* 16px */&lt;/span&gt;
  &lt;span class="py"&gt;--text-lg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="m"&gt;1.125rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;/* 18px */&lt;/span&gt;
  &lt;span class="py"&gt;--text-xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="m"&gt;1.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c"&gt;/* 20px */&lt;/span&gt;
  &lt;span class="py"&gt;--text-2xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c"&gt;/* 24px */&lt;/span&gt;
  &lt;span class="py"&gt;--text-3xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;1.875rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;/* 30px */&lt;/span&gt;
  &lt;span class="py"&gt;--text-4xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;2.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c"&gt;/* 36px */&lt;/span&gt;
  &lt;span class="py"&gt;--text-5xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;3rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c"&gt;/* 48px */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  rem in Media Queries (The Part Nobody Talks About)
&lt;/h2&gt;

&lt;p&gt;Here's something that trips people up: media queries accept &lt;code&gt;rem&lt;/code&gt; too — and it's actually the better choice.&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;/* Works, but doesn't scale with user font preference */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Scales with user preference */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;48rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;px&lt;/code&gt; breakpoints: if a user bumps their font size to 20px, your layout still breaks at 768 device pixels regardless of their preference.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;rem&lt;/code&gt; breakpoints: the breakpoint itself scales. At &lt;code&gt;20px&lt;/code&gt; root, &lt;code&gt;48rem = 960px&lt;/code&gt; — your layout adapts. The user's preference propagates all the way through your responsive design.&lt;/p&gt;

&lt;p&gt;Quick conversion for the standard breakpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;480px  = 30rem
640px  = 40rem
768px  = 48rem
1024px = 64rem
1280px = 80rem
1440px = 90rem
1536px = 96rem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Tailwind Users: Arbitrary Values + rem
&lt;/h2&gt;

&lt;p&gt;Tailwind's preset scale already uses &lt;code&gt;rem&lt;/code&gt; internally — &lt;code&gt;text-base&lt;/code&gt; is &lt;code&gt;1rem&lt;/code&gt;, &lt;code&gt;text-xl&lt;/code&gt; is &lt;code&gt;1.25rem&lt;/code&gt;, and so on. But when a design spec calls for something off the preset scale, you need arbitrary values:&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-[2.25rem] leading-[2.75rem]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Heading&lt;span class="nt"&gt;&amp;lt;/h1&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;"mt-[1.875rem] px-[1.5rem]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Content&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;The converter I mentioned generates the Tailwind arbitrary value string automatically alongside the standard CSS — so you don't have to manually format it.&lt;/p&gt;

&lt;p&gt;If you're on Tailwind v4 and building a custom &lt;code&gt;@theme&lt;/code&gt; block, those tokens go in as &lt;code&gt;rem&lt;/code&gt; values too:&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="k"&gt;@theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--font-size-display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c"&gt;/* 48px */&lt;/span&gt;
  &lt;span class="py"&gt;--font-size-heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c"&gt;/* 36px */&lt;/span&gt;
  &lt;span class="py"&gt;--spacing-section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c"&gt;/* 80px */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  PostCSS Automation (For Large Codebases)
&lt;/h2&gt;

&lt;p&gt;If you're migrating a legacy codebase with thousands of &lt;code&gt;px&lt;/code&gt; declarations, doing it manually isn't realistic. There's a PostCSS plugin — &lt;code&gt;postcss-pxtorem&lt;/code&gt; — that converts &lt;code&gt;px&lt;/code&gt; to &lt;code&gt;rem&lt;/code&gt; at build time.&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;postcss-pxtorem &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// postcss.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postcss-pxtorem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;rootValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;propList&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;font-size&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;line-height&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;letter-spacing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="c1"&gt;// Leave margins/paddings in px if you want&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;You write &lt;code&gt;font-size: 24px&lt;/code&gt; in development, it outputs &lt;code&gt;font-size: 1.5rem&lt;/code&gt; in production. Same formula this tool uses — just automated.&lt;/p&gt;

&lt;p&gt;Be careful with the &lt;code&gt;propList&lt;/code&gt; — don't blindly convert &lt;em&gt;everything&lt;/em&gt; to rem. Borders, icon sizes, and elements that should never scale usually want to stay in &lt;code&gt;px&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;rem&lt;/code&gt; for font sizes and spacing — it respects user browser preferences and satisfies WCAG&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;px&lt;/code&gt; for borders, shadows, and things that genuinely shouldn't scale&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rem = px ÷ base font size&lt;/code&gt; (default base = &lt;code&gt;16px&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Don't use the &lt;code&gt;62.5%&lt;/code&gt; html trick on new projects — it's an accessibility anti-pattern&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rem&lt;/code&gt; works in media queries too — and it's better for accessibility&lt;/li&gt;
&lt;li&gt;For bulk conversions or a non-standard base, use a proper tool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→ &lt;a href="https://www.webtoolshub.online/tools/px-to-rem-converter" rel="noopener noreferrer"&gt;&lt;strong&gt;WebToolsHub — PX to REM Converter (free, bidirectional, bulk)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you use CSS custom properties for design tokens, our &lt;a href="https://www.webtoolshub.online/blog/css-variables-design-tokens-dark-mode-system-2026" rel="noopener noreferrer"&gt;CSS Variables &amp;amp; Dark Mode guide&lt;/a&gt; covers how to wire up a full token system in Next.js. And if you're migrating to Tailwind from a pixel-heavy codebase, the &lt;a href="https://www.webtoolshub.online/tools/css-to-tailwind-converter" rel="noopener noreferrer"&gt;CSS to Tailwind converter&lt;/a&gt; handles the class-mapping layer.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;css&lt;/code&gt; &lt;code&gt;webdev&lt;/code&gt; &lt;code&gt;frontend&lt;/code&gt; &lt;code&gt;beginners&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Google Antigravity IDE 2.0 Broke My Next.js Setup — Here's How I Fixed It (And Whether It's Worth Using)</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Thu, 11 Jun 2026 08:43:20 +0000</pubDate>
      <link>https://dev.to/webtoolshub/google-antigravity-ide-20-broke-my-nextjs-setup-heres-how-i-fixed-it-and-whether-its-worth-28l</link>
      <guid>https://dev.to/webtoolshub/google-antigravity-ide-20-broke-my-nextjs-setup-heres-how-i-fixed-it-and-whether-its-worth-28l</guid>
      <description>&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%2Fg6r3jh2ivm6yhpy0q19j.webp" 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%2Fg6r3jh2ivm6yhpy0q19j.webp" alt="Google Antigravity IDE 2.0 Complete Guide for Next.js Developers (2026)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On May 20, 2026, I opened my project in Antigravity IDE and found something unexpected. My terminal was gone. The error indicators had disappeared. The familiar VS Code-style interface was replaced with a chat panel and a "Manager View" I hadn't asked for.&lt;/p&gt;

&lt;p&gt;Google had auto-updated Antigravity to 2.0 overnight — without warning — and broken the workflow I'd spent three months building.&lt;/p&gt;

&lt;p&gt;I spent the next few hours figuring out what changed and how to get back to productive work. This is everything I learned.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Antigravity 2.0 Actually Is
&lt;/h2&gt;

&lt;p&gt;Most developers think Antigravity 2.0 is just an updated AI editor. It's not.&lt;/p&gt;

&lt;p&gt;Announced at Google I/O on May 19, 2026, it's now a &lt;strong&gt;five-surface agent orchestration platform&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Desktop App&lt;/strong&gt; — the new default, rebuilt from scratch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Antigravity CLI&lt;/strong&gt; — replaces Gemini CLI on June 18, 2026&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SDK&lt;/strong&gt; — for embedding agents in your own tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Managed Agents API&lt;/strong&gt; — hosted agent infrastructure inside Gemini API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise Agent Platform&lt;/strong&gt; — Google Cloud integration layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The original VS Code-based IDE still exists but you have to download it separately now. This is why thousands of devs woke up to broken setups — the auto-update installed 2.0 and removed the traditional IDE as the primary surface without any migration path.&lt;/p&gt;

&lt;p&gt;If you're currently dealing with a blank screen or broken terminal after the update, I wrote a separate &lt;a href="https://www.webtoolshub.online/blog/fix-antigravity-ide-blank-screen-after-update" rel="noopener noreferrer"&gt;Antigravity IDE blank screen fix guide&lt;/a&gt; that covers the most common post-update issues step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Manager View vs Editor View — The Key Mental Shift
&lt;/h2&gt;

&lt;p&gt;The biggest adjustment in 2.0 is the interface split.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manager View&lt;/strong&gt; (new default) is a mission control dashboard. You describe a task in natural language, Antigravity dispatches agents to plan and execute, and you get review checkpoints before anything gets written to disk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Editor View&lt;/strong&gt; is the direct coding surface — closer to Antigravity 1.x. You access it from Manager View or the Editor tab.&lt;/p&gt;

&lt;p&gt;The mental shift: &lt;strong&gt;you're no longer typing code with AI assistance. You're directing agents who write code on your behalf.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For repetitive scaffolding tasks this is faster. For precise, nuanced edits where you know exactly what you want — Editor View or &lt;a href="https://www.webtoolshub.online/blog/claude-code-skills-complete-guide-2026" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; is more efficient.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting Up AGENTS.md for Next.js (The Most Important Step)
&lt;/h2&gt;

&lt;p&gt;The single most important config step is your &lt;code&gt;AGENTS.md&lt;/code&gt; file. Without it, agents default to generic Next.js conventions that probably don't match your project.&lt;/p&gt;

&lt;p&gt;Here's what works well for a Next.js 15 App Router project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# My Project (Next.js 15 App Router)&lt;/span&gt;

&lt;span class="gu"&gt;## Stack&lt;/span&gt;
Next.js 15.3 App Router, TypeScript 5.9 strict, Tailwind CSS v4,
MongoDB with Mongoose, deployed on Vercel

&lt;span class="gu"&gt;## Commands&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Dev: &lt;span class="sb"&gt;`npm run dev`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Type check: &lt;span class="sb"&gt;`npm run typecheck`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Lint: &lt;span class="sb"&gt;`npm run lint`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Build: &lt;span class="sb"&gt;`npm run build`&lt;/span&gt;

&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Named exports only, never default exports
&lt;span class="p"&gt;-&lt;/span&gt; Server components by default, &lt;span class="sb"&gt;`'use client'`&lt;/span&gt; only when necessary
&lt;span class="p"&gt;-&lt;/span&gt; TypeScript strict mode — no &lt;span class="sb"&gt;`any`&lt;/span&gt; types
&lt;span class="p"&gt;-&lt;/span&gt; Tailwind utility classes only, no inline styles
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`@/`&lt;/span&gt; alias for all internal imports

&lt;span class="gu"&gt;## Boundaries&lt;/span&gt;
&lt;span class="gu"&gt;### Ask before doing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Changes to &lt;span class="sb"&gt;`/src/models/`&lt;/span&gt; — schema changes affect all data
&lt;span class="p"&gt;-&lt;/span&gt; New npm dependencies

&lt;span class="gu"&gt;### Never do&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Add TypeScript &lt;span class="sb"&gt;`any`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Direct database edits
&lt;span class="p"&gt;-&lt;/span&gt; Modify &lt;span class="sb"&gt;`.env.local`&lt;/span&gt; values in code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a deeper dive, the &lt;a href="https://www.webtoolshub.online/blog/what-is-agents-md-how-to-write-nextjs-2026" rel="noopener noreferrer"&gt;complete AGENTS.md guide for Next.js&lt;/a&gt; has copy-paste templates for all five sections.&lt;/p&gt;




&lt;h2&gt;
  
  
  Running a Multi-Agent Mission (Real Example)
&lt;/h2&gt;

&lt;p&gt;This is where Antigravity 2.0 genuinely shines. Here's a real mission I ran on my project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mission: "Add a new blog category called 'Tools' with its own
listing page, update the navigation, and add a category filter
to the existing blog listing page."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without Antigravity, this is a 45-minute task across four files. With a well-scoped mission, Antigravity dispatches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;planning agent&lt;/strong&gt; that maps required changes across your codebase&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;UI agent&lt;/strong&gt; handling navigation update and filter component&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;routing agent&lt;/strong&gt; creating the new category page and dynamic route&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;verification agent&lt;/strong&gt; running your type checker and linter after each change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;checkpoint system&lt;/strong&gt; is what makes this not "vibe coding." Before the agent writes to any file, it shows you a plan — what it intends to change and why. You approve, redirect, or reject before execution.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Keep missions scoped. "Add a blog category with listing page" = good mission. "Refactor the entire blog system" = too broad, parallel agents start touching overlapping files.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Antigravity 2.0 vs Cursor vs Claude Code — Honest Verdict
&lt;/h2&gt;

&lt;p&gt;I use all three. Here's where each actually wins for Next.js:&lt;/p&gt;

&lt;h3&gt;
  
  
  Daily coding work
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cursor wins.&lt;/strong&gt; Faster completions, more fluid chat, VS Code compatibility means your extensions and muscle memory work. Cursor has 18 months more polish on its editor experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-file agentic tasks
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Antigravity wins on parallel execution.&lt;/strong&gt; For tasks spanning 5+ files with a clear spec, Manager View is genuinely faster. For accuracy on complex tasks, &lt;a href="https://www.webtoolshub.online/blog/claude-code-vs-cursor-vs-github-copilot-2026" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; still has the higher SWE-Bench score but runs sequentially.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Antigravity wins on free tier.&lt;/strong&gt; Free includes Gemini 3.5 Flash, Claude Sonnet 4.6, and GPT-OSS 120B with rotating rate limits. Cursor's free tier is far more restricted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next.js App Router specifically
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Claude Code + Cursor is still the strongest combo.&lt;/strong&gt; Claude Code's understanding of App Router conventions, server components, and server actions is consistently more accurate than Gemini 3.5. For a TypeScript-heavy Next.js codebase, this matters a lot.&lt;/p&gt;

&lt;p&gt;Want the full breakdown of all the 2026 AI coding tools? The &lt;a href="https://www.webtoolshub.online/blog/claude-code-vs-cursor-vs-github-copilot-2026" rel="noopener noreferrer"&gt;complete comparison of Claude Code vs Cursor vs GitHub Copilot&lt;/a&gt; has benchmark scores and workflow recommendations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing (June 2026)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Models&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Gemini 3.5 Flash, Claude Sonnet 4.6, GPT-OSS 120B&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Individual&lt;/td&gt;
&lt;td&gt;+ Gemini 3.1 Pro, Claude Opus 4.8, background tasks&lt;/td&gt;
&lt;td&gt;~$19/mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credit packs&lt;/td&gt;
&lt;td&gt;Burst usage without subscription&lt;/td&gt;
&lt;td&gt;Pay as you go&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;My recommendation:&lt;/strong&gt; Start with the free tier for two weeks on your actual project before paying. The rate limits are annoying but sufficient for evaluating fit. Use the &lt;a href="https://www.webtoolshub.online/tools/llm-api-cost-calculator" rel="noopener noreferrer"&gt;LLM API Cost Calculator&lt;/a&gt; to compare credit-pack costs vs direct API usage.&lt;/p&gt;




&lt;h2&gt;
  
  
  Known Issues Right Now (June 2026)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Terminal missing after update&lt;/strong&gt; — The terminal panel was removed in 2.0. Use Editor View or run a separate terminal window. The &lt;a href="https://www.webtoolshub.online/blog/fix-antigravity-ide-blank-screen-after-update" rel="noopener noreferrer"&gt;post-update fix guide&lt;/a&gt; has recovery steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context window lag&lt;/strong&gt; — Long sessions accumulate history and slow the UI. Fix: restart session every 45-60 minutes. AGENTS.md reloads automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemini CLI shutdown on June 18&lt;/strong&gt; — If you're using Gemini CLI, migrate to Antigravity CLI before the cutoff. Commands map directly, same functionality under the &lt;code&gt;agy&lt;/code&gt; prefix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No MCP support&lt;/strong&gt; — Unlike Claude Code and &lt;a href="https://www.webtoolshub.online/blog/github-copilot-agent-mode-2026-vs-cursor" rel="noopener noreferrer"&gt;GitHub Copilot Agent Mode&lt;/a&gt;, Antigravity 2.0 has no &lt;a href="https://www.webtoolshub.online/blog/what-is-mcp-model-context-protocol-guide-2026" rel="noopener noreferrer"&gt;MCP server&lt;/a&gt; support. If your workflow uses MCP integrations (Stripe, Figma, databases), you'll need a different tool for those tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parallel agents overlapping files&lt;/strong&gt; — In multi-agent missions, agents occasionally try to edit the same files and create conflicts. Keep mission scope tight — one feature area per mission.&lt;/p&gt;




&lt;h2&gt;
  
  
  Should You Switch from Cursor?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No, not as a full replacement.&lt;/strong&gt; But as a complementary tool for specific tasks — yes.&lt;/p&gt;

&lt;p&gt;The workflow I'm running right now: Antigravity 2.0 for scaffolding new pages, Cursor for component refinement, Claude Code for complex server actions and data layer work. Each one is clearly better at its lane, and a shared AGENTS.md means all three agents understand my project conventions from the first prompt.&lt;/p&gt;

&lt;p&gt;If you're evaluating the full 2026 AI coding landscape, also check out the &lt;a href="https://www.webtoolshub.online/blog/aws-kiro-ide-complete-guide-cursor-comparison-2026" rel="noopener noreferrer"&gt;AWS Kiro IDE comparison&lt;/a&gt; and the &lt;a href="https://www.webtoolshub.online/blog/google-io-2026-developer-announcements" rel="noopener noreferrer"&gt;Google I/O 2026 developer announcements&lt;/a&gt; for more context on where these tools are heading.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What's your setup right now? Still on Cursor, trying Antigravity, or using something else entirely? Drop it in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>ai</category>
      <category>claude</category>
      <category>webdev</category>
    </item>
    <item>
      <title>AGENTS.md: The One File That Makes AI Coding Agents Actually Understand Your Next.js Project</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Thu, 11 Jun 2026 07:38:59 +0000</pubDate>
      <link>https://dev.to/webtoolshub/agentsmd-the-one-file-that-makes-ai-coding-agents-actually-understand-your-nextjs-project-2edk</link>
      <guid>https://dev.to/webtoolshub/agentsmd-the-one-file-that-makes-ai-coding-agents-actually-understand-your-nextjs-project-2edk</guid>
      <description>&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%2F0xgdt7yidispvyv83ti3.webp" 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%2F0xgdt7yidispvyv83ti3.webp" alt="What is AGENTS.md How to Write One for Your Next.js Project (2026)"&gt;&lt;/a&gt;&lt;br&gt;
You've been here. You open Claude Code, assign it a task — "add validation to the signup form" — and it comes back with a technically correct solution that uses the wrong validation library, breaks three of your naming conventions, and imports from a module you deprecated six months ago.&lt;/p&gt;

&lt;p&gt;The fix isn't a better prompt. It's &lt;strong&gt;AGENTS.md&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One file at your repo root. Every AI coding agent reads it at session start. Projects with a properly written one average &lt;strong&gt;35–55% fewer agent-generated bugs&lt;/strong&gt; — and that number tracks with what I've seen in practice.&lt;/p&gt;

&lt;p&gt;Here's everything you need to know, with copy-paste Next.js templates.&lt;/p&gt;


&lt;h2&gt;
  
  
  What AGENTS.md Actually Is
&lt;/h2&gt;

&lt;p&gt;Plain Markdown. No YAML frontmatter. No special syntax. Just headings and bullet points that tell a coding agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What your stack is (exact versions)&lt;/li&gt;
&lt;li&gt;Which commands to run&lt;/li&gt;
&lt;li&gt;What conventions to follow&lt;/li&gt;
&lt;li&gt;What to never touch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It lives at your repo root — same level as &lt;code&gt;package.json&lt;/code&gt;. Every major AI coding tool reads it as of 2026:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Support&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;✅ Native (priority over CLAUDE.md)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Copilot Agent Mode&lt;/td&gt;
&lt;td&gt;✅ Full (Agent HQ shared context)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;td&gt;✅ Priority over .cursorrules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI Codex (Agent HQ)&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windsurf&lt;/td&gt;
&lt;td&gt;⚠️ Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  Why It Replaced .cursorrules and CLAUDE.md
&lt;/h2&gt;

&lt;p&gt;Before AGENTS.md, you maintained a different file per tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.cursorrules                          ← Cursor
CLAUDE.md                             ← Claude Code
.github/copilot-instructions.md       ← Copilot
GEMINI.md                             ← Gemini
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every tool switch meant duplicating content. Instructions drifted. New teammates had to hunt for "the real rules."&lt;/p&gt;

&lt;p&gt;AGENTS.md is the cross-tool standard — one file, every agent. You can keep your old files for backwards compatibility (tools still read them), but AGENTS.md takes priority when both exist.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Minimal Structure That Actually Moves the Needle
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project Name&lt;/span&gt;

&lt;span class="gu"&gt;## Stack&lt;/span&gt;
Next.js 15.3 App Router, TypeScript 5.9 strict, Tailwind CSS v4,
Prisma 6.x, PostgreSQL, Zod 3.x, NextAuth v5

&lt;span class="gu"&gt;## Commands&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Dev: &lt;span class="sb"&gt;`npm run dev`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Type check: &lt;span class="sb"&gt;`npm run typecheck`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Lint: &lt;span class="sb"&gt;`npm run lint`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Test: &lt;span class="sb"&gt;`npm run test`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Build: &lt;span class="sb"&gt;`npm run build`&lt;/span&gt;

&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Named exports only — never default exports
&lt;span class="p"&gt;-&lt;/span&gt; Server components by default, &lt;span class="sb"&gt;`'use client'`&lt;/span&gt; only when hooks/browser APIs needed
&lt;span class="p"&gt;-&lt;/span&gt; Zod for all validation — never manual type guards
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`@/`&lt;/span&gt; alias for all internal imports

&lt;span class="gu"&gt;## Boundaries&lt;/span&gt;
&lt;span class="gu"&gt;### Ask before doing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Changes to &lt;span class="sb"&gt;`prisma/schema.prisma`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; New npm dependencies
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`next.config.ts`&lt;/span&gt; changes

&lt;span class="gu"&gt;### Never do&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Add TypeScript &lt;span class="sb"&gt;`any`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Modify &lt;span class="sb"&gt;`/lib/legacy/`&lt;/span&gt; — deprecated
&lt;span class="p"&gt;-&lt;/span&gt; Use &lt;span class="sb"&gt;`localStorage`&lt;/span&gt; directly — use &lt;span class="sb"&gt;`/lib/storage/client.ts`&lt;/span&gt; wrapper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under 60 lines. Prevents the most common class of AI agent failures.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Five Sections That Matter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Stack — Be Specific About Versions
&lt;/h3&gt;

&lt;p&gt;Next.js 15 App Router behaves completely differently from Next.js 14. An agent that doesn't know which you're on will generate server action syntax that doesn't compile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Stack&lt;/span&gt;
Next.js 15.3 App Router, TypeScript 5.9 (strict mode), Tailwind CSS v4,
Prisma 6.x with PostgreSQL, Zod 3.x, NextAuth v5, Vitest, Playwright,
deployed on Vercel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Commands — Exact Executables With Flags
&lt;/h3&gt;

&lt;p&gt;Agents use these to verify their own work. They run your type checker and linter after making changes. If you don't provide exact commands, they guess — and guesses fail on custom setups.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Commands&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Install: &lt;span class="sb"&gt;`npm install`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Dev server: &lt;span class="sb"&gt;`npm run dev`&lt;/span&gt; (port 3000)
&lt;span class="p"&gt;-&lt;/span&gt; Type check: &lt;span class="sb"&gt;`npm run typecheck`&lt;/span&gt; (tsc --noEmit)
&lt;span class="p"&gt;-&lt;/span&gt; Lint: &lt;span class="sb"&gt;`npm run lint`&lt;/span&gt; (eslint + prettier check)
&lt;span class="p"&gt;-&lt;/span&gt; Format: &lt;span class="sb"&gt;`npm run format`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Test (unit): &lt;span class="sb"&gt;`npm run test`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Test (e2e): &lt;span class="sb"&gt;`npm run test:e2e`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Build: &lt;span class="sb"&gt;`npm run build`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; DB sync (dev only): &lt;span class="sb"&gt;`npx prisma db push`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; DB migrate: &lt;span class="sb"&gt;`npx prisma migrate dev --name &amp;lt;description&amp;gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Conventions — Specific Rules, Not Generic Advice
&lt;/h3&gt;

&lt;p&gt;"Write clean code" means nothing. "Named exports only" is a rule an agent can follow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Named exports only: &lt;span class="sb"&gt;`export function Foo()`&lt;/span&gt;, never &lt;span class="sb"&gt;`export default`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Server components by default — add &lt;span class="sb"&gt;`'use client'`&lt;/span&gt; only for hooks/browser APIs
&lt;span class="p"&gt;-&lt;/span&gt; Server actions in &lt;span class="sb"&gt;`/app/actions/`&lt;/span&gt; — one file per domain (auth.ts, user.ts)
&lt;span class="p"&gt;-&lt;/span&gt; API routes in &lt;span class="sb"&gt;`/app/api/`&lt;/span&gt; — REST conventions
&lt;span class="p"&gt;-&lt;/span&gt; Zod schema for every form and API input — no manual &lt;span class="sb"&gt;`as Type`&lt;/span&gt; assertions
&lt;span class="p"&gt;-&lt;/span&gt; shadcn/ui components from &lt;span class="sb"&gt;`/components/ui/`&lt;/span&gt; only — extend with wrappers,
  never modify the source files
&lt;span class="p"&gt;-&lt;/span&gt; DB queries only in &lt;span class="sb"&gt;`/lib/db/`&lt;/span&gt; — never inline in components or server actions
&lt;span class="p"&gt;-&lt;/span&gt; Error boundaries at route segment level
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Boundaries — Three Tiers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Boundaries&lt;/span&gt;

&lt;span class="gu"&gt;### Ask before doing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`prisma/schema.prisma`&lt;/span&gt; changes — migrations are version-controlled
&lt;span class="p"&gt;-&lt;/span&gt; New npm dependencies — check if existing package covers the need
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`next.config.ts`&lt;/span&gt; changes — affects entire build
&lt;span class="p"&gt;-&lt;/span&gt; Architectural changes across multiple modules

&lt;span class="gu"&gt;### Never do&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Add TypeScript &lt;span class="sb"&gt;`any`&lt;/span&gt; — fix the type or ask for help
&lt;span class="p"&gt;-&lt;/span&gt; Import from &lt;span class="sb"&gt;`/lib/legacy/`&lt;/span&gt; — being phased out, do not touch
&lt;span class="p"&gt;-&lt;/span&gt; Use &lt;span class="sb"&gt;`localStorage`&lt;/span&gt; or &lt;span class="sb"&gt;`sessionStorage`&lt;/span&gt; directly — use &lt;span class="sb"&gt;`/lib/storage/client.ts`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Hardcode env values — validate everything through &lt;span class="sb"&gt;`/lib/env.ts`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Modify &lt;span class="sb"&gt;`/components/ui/`&lt;/span&gt; files — these are shadcn sources, use wrappers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Testing — Framework + What Not to Mock
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Testing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Framework: Vitest + @testing-library/react
&lt;span class="p"&gt;-&lt;/span&gt; Unit: &lt;span class="sb"&gt;`/tests/unit/`&lt;/span&gt; — pure functions only
&lt;span class="p"&gt;-&lt;/span&gt; Integration: &lt;span class="sb"&gt;`/tests/integration/`&lt;/span&gt; — full server actions, real DB,
  transactions roll back after each test
&lt;span class="p"&gt;-&lt;/span&gt; E2E: Playwright in &lt;span class="sb"&gt;`/tests/e2e/`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Never mock Prisma — use test DB with rollback transactions
&lt;span class="p"&gt;-&lt;/span&gt; Mock external APIs with MSW (Mock Service Worker)
&lt;span class="p"&gt;-&lt;/span&gt; Coverage: 80% for /lib/, 60% for /app/
&lt;span class="p"&gt;-&lt;/span&gt; Always run &lt;span class="sb"&gt;`npm run typecheck &amp;amp;&amp;amp; npm run lint &amp;amp;&amp;amp; npm run test`&lt;/span&gt; before done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Complete Next.js App Router Template (Copy This)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# My Next.js App&lt;/span&gt;

&lt;span class="gu"&gt;## Stack&lt;/span&gt;
Next.js 15.3 App Router, TypeScript 5.9 strict, Tailwind CSS v4,
Prisma 6.x, PostgreSQL, NextAuth v5, Zod 3.x, Vitest, Playwright

&lt;span class="gu"&gt;## Project Structure&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`/app/`&lt;/span&gt; — Pages, layouts, route handlers
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`/app/actions/`&lt;/span&gt; — Server actions (one file per domain)
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`/app/api/`&lt;/span&gt; — REST API routes
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`/components/ui/`&lt;/span&gt; — shadcn/ui (do not modify)
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`/components/`&lt;/span&gt; — Custom components
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`/lib/`&lt;/span&gt; — Shared utilities
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`/lib/db/`&lt;/span&gt; — All Prisma queries live here only
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`/lib/env.ts`&lt;/span&gt; — Zod-validated env variables
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`/tests/`&lt;/span&gt; — unit/, integration/, e2e/

&lt;span class="gu"&gt;## Commands&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Dev: &lt;span class="sb"&gt;`npm run dev`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Type check: &lt;span class="sb"&gt;`npm run typecheck`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Lint: &lt;span class="sb"&gt;`npm run lint`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Test: &lt;span class="sb"&gt;`npm run test`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Build: &lt;span class="sb"&gt;`npm run build`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; DB push (dev): &lt;span class="sb"&gt;`npx prisma db push`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; DB migrate: &lt;span class="sb"&gt;`npx prisma migrate dev --name &amp;lt;description&amp;gt;`&lt;/span&gt;

&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Named exports only, never default exports
&lt;span class="p"&gt;-&lt;/span&gt; Server components by default, &lt;span class="sb"&gt;`'use client'`&lt;/span&gt; only when necessary
&lt;span class="p"&gt;-&lt;/span&gt; All input validated with Zod before processing
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`@/`&lt;/span&gt; alias for all internal imports
&lt;span class="p"&gt;-&lt;/span&gt; PascalCase for component files, camelCase for utility files
&lt;span class="p"&gt;-&lt;/span&gt; No inline styles — Tailwind utility classes only

&lt;span class="gu"&gt;## Boundaries&lt;/span&gt;

&lt;span class="gu"&gt;### Ask before doing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`prisma/schema.prisma`&lt;/span&gt; changes
&lt;span class="p"&gt;-&lt;/span&gt; New npm dependencies
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`next.config.ts`&lt;/span&gt; changes

&lt;span class="gu"&gt;### Never do&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Add &lt;span class="sb"&gt;`any`&lt;/span&gt; type — fix it properly
&lt;span class="p"&gt;-&lt;/span&gt; Touch &lt;span class="sb"&gt;`/lib/legacy/`&lt;/span&gt; — deprecated
&lt;span class="p"&gt;-&lt;/span&gt; Use &lt;span class="sb"&gt;`localStorage`&lt;/span&gt; directly — use &lt;span class="sb"&gt;`/lib/storage/client.ts`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Hardcode env values — use &lt;span class="sb"&gt;`/lib/env.ts`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Modify &lt;span class="sb"&gt;`/components/ui/`&lt;/span&gt; — wrap instead

&lt;span class="gu"&gt;## Testing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Vitest for unit + integration tests
&lt;span class="p"&gt;-&lt;/span&gt; Playwright for E2E
&lt;span class="p"&gt;-&lt;/span&gt; Never mock Prisma — use test DB with rollbacks
&lt;span class="p"&gt;-&lt;/span&gt; MSW for external API mocking
&lt;span class="p"&gt;-&lt;/span&gt; Run typecheck + lint + test before marking any task done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Monorepo Setup — Running Multiple Agents in Parallel
&lt;/h2&gt;

&lt;p&gt;GitHub Agent HQ lets you run Claude, Codex, and Copilot simultaneously. Without scoped AGENTS.md files, two agents will edit the same file and create conflicts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project/
├── AGENTS.md              # Shared: git conventions, CI commands, global rules
├── apps/
│   ├── web/
│   │   └── AGENTS.md      # "Frontend only. Don't touch /api/ or /packages/"
│   └── api/
│       └── AGENTS.md      # "API routes only. Don't touch /web/"
└── packages/
    └── ui/
        └── AGENTS.md      # "UI library only. No business logic here."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent reads the root file first (shared context), then the nearest scoped file (domain-specific rules). Root-level context + scoped boundaries = no cross-domain conflicts.&lt;/p&gt;




&lt;h2&gt;
  
  
  AGENTS.md vs CLAUDE.md vs .cursorrules — Migration Guide
&lt;/h2&gt;

&lt;p&gt;If you're already using one of the older formats:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From .cursorrules:&lt;/strong&gt;&lt;br&gt;
Copy your content into AGENTS.md. Restructure into the five sections above. Delete .cursorrules or leave it — Cursor will ignore it once AGENTS.md exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From CLAUDE.md:&lt;/strong&gt;&lt;br&gt;
Keep CLAUDE.md if you want (Claude Code reads both). But put your main content in AGENTS.md and make CLAUDE.md a one-liner: &lt;code&gt;@AGENTS.md&lt;/code&gt; — this tells Claude Code to read the shared file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From copilot-instructions.md:&lt;/strong&gt;&lt;br&gt;
Keep it for non-Agent HQ Copilot workflows. Migrate your core content to AGENTS.md. Agent HQ sessions use AGENTS.md as the primary context.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Biggest Mistakes (And How to Avoid Them)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Writing prose instead of rules&lt;/strong&gt;&lt;br&gt;
❌ "Follow best practices for error handling"&lt;br&gt;
✅ "Throw typed errors in server actions, catch at the route segment error boundary"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listing every possible command&lt;/strong&gt;&lt;br&gt;
Only include commands the agent actually uses during normal work. A 40-command list means the agent has to parse it every session — wasted context tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not updating it when the stack changes&lt;/strong&gt;&lt;br&gt;
An AGENTS.md that says "use Prisma 5" when you're on Prisma 6 will make the agent generate deprecated syntax confidently. Treat it like code — update it in the same PR that changes the dependency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Making it too long&lt;/strong&gt;&lt;br&gt;
Under 150 lines is the target. If you're writing paragraphs, you've crossed from agent instructions into human documentation. Move that content to README.md.&lt;/p&gt;


&lt;h2&gt;
  
  
  Verify Your Setup
&lt;/h2&gt;

&lt;p&gt;After writing your AGENTS.md, run this quick check with Claude Code or Cursor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Read my AGENTS.md and tell me: 
1. What command do you use to run tests?
2. Where do database queries live?  
3. What should you never modify without asking?
4. What validation library do you use?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the agent answers correctly from the file — you're done. If it gets any wrong — that section needs more clarity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tools That Work Well Alongside AGENTS.md
&lt;/h2&gt;

&lt;p&gt;If you're building agentic workflows that go beyond single-file edits, here are two things worth setting up alongside your AGENTS.md:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt; — connects Claude Code and other agents to external tools, databases, and APIs. Your AGENTS.md defines the project conventions; MCP gives agents the tools to act on them. The &lt;a href="https://www.webtoolshub.online/blog/what-is-mcp-model-context-protocol-guide-2026" rel="noopener noreferrer"&gt;MCP complete guide on WebToolsHub&lt;/a&gt; covers setup from scratch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Code agent workflows&lt;/strong&gt; — for multi-step autonomous tasks that go beyond what Copilot handles inline. The &lt;a href="https://www.webtoolshub.online/blog/claude-code-skills-complete-guide-2026" rel="noopener noreferrer"&gt;Claude Code skills guide&lt;/a&gt; covers how to structure long-running agent sessions so they stay aligned with your conventions — which is exactly what a good AGENTS.md enables.&lt;/p&gt;

&lt;p&gt;For the broader picture of how AGENTS.md fits into a full agentic development workflow — task assignment, parallel agents, review loops — the &lt;a href="https://www.webtoolshub.online/blog/guide-to-autonomous-ai-agents-agentic-workflows" rel="noopener noreferrer"&gt;agentic AI workflows guide on WebToolsHub&lt;/a&gt; covers the architecture end to end.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md checklist:
✅ Stack section with exact versions
✅ Commands section with exact flags (not descriptions)
✅ Conventions: specific rules, not generic advice
✅ Boundaries: Ask / Never do tiers
✅ Testing: framework + what NOT to mock
✅ Under 150 lines total
✅ Committed to version control
✅ Updated in same PR as stack changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the file. One-time 20-minute investment. Every agent that touches your project from now on starts with full project context.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Full guide with FAQ, Claude Fable 5 integration notes, and advanced monorepo patterns on &lt;a href="https://www.webtoolshub.online/blog/what-is-agents-md-how-to-write-nextjs-2026" rel="noopener noreferrer"&gt;WebToolsHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>ai</category>
      <category>claude</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Stop Running Unvalidated SQL Against Production Use a Free Browser-Based Validator Instead</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Thu, 11 Jun 2026 03:47:14 +0000</pubDate>
      <link>https://dev.to/webtoolshub/stop-running-unvalidated-sql-against-production-use-a-free-browser-based-validator-instead-5d3p</link>
      <guid>https://dev.to/webtoolshub/stop-running-unvalidated-sql-against-production-use-a-free-browser-based-validator-instead-5d3p</guid>
      <description>&lt;p&gt;Let me describe a workflow I've watched countless developers use - including myself, more times than I want to admit.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a SQL query in your editor&lt;/li&gt;
&lt;li&gt;Eyeball it once&lt;/li&gt;
&lt;li&gt;Copy-paste it directly into a production database client&lt;/li&gt;
&lt;li&gt;Hit execute&lt;/li&gt;
&lt;li&gt;Wait&lt;/li&gt;
&lt;li&gt;Either relief or regret&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you've never felt the specific stomach-drop of watching a &lt;code&gt;DELETE&lt;/code&gt; run without a &lt;code&gt;WHERE&lt;/code&gt; clause, consider yourself lucky. It's an experience that tends to permanently change your habits — but ideally that change happens &lt;em&gt;before&lt;/em&gt; the incident, not after.&lt;/p&gt;

&lt;p&gt;This post is about building better SQL validation habits, understanding dialect differences that cause silent bugs, and introducing a free tool I built specifically for this problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Validation Gap in Most Dev Workflows
&lt;/h2&gt;

&lt;p&gt;Most modern development workflows have decent safety nets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript&lt;/strong&gt; catches type errors at compile time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESLint&lt;/strong&gt; flags code quality issues before you commit
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jest/Vitest&lt;/strong&gt; runs tests before your CI pipeline deploys&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zod&lt;/strong&gt; validates API payloads at runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But SQL? SQL often gets none of this. You write it, you read it once, and you run it. The "test environment" is frequently just production with a slightly nervous attitude.&lt;/p&gt;

&lt;p&gt;This is particularly ironic because SQL errors are often &lt;em&gt;more&lt;/em&gt; consequential than application code errors. A runtime error in your React component shows a broken UI. A malformed &lt;code&gt;UPDATE&lt;/code&gt; with the wrong &lt;code&gt;WHERE&lt;/code&gt; clause modifies data that you may never be able to fully recover.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tool: SQL Query Validator on WebToolsHub
&lt;/h2&gt;

&lt;p&gt;I built the &lt;a href="https://www.webtoolshub.online/tools/sql-query-validator" rel="noopener noreferrer"&gt;SQL Query Validator&lt;/a&gt; to close this gap. It's free, browser-based, and runs 100% client-side — your queries never leave your machine.&lt;/p&gt;

&lt;p&gt;Here's what it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Validates SQL syntax against your chosen dialect&lt;/li&gt;
&lt;li&gt;✅ Shows errors with exact line numbers and plain-English messages&lt;/li&gt;
&lt;li&gt;✅ Formats queries in one step (Format + Validate)&lt;/li&gt;
&lt;li&gt;✅ Supports MySQL, PostgreSQL, SQLite, SQL Server&lt;/li&gt;
&lt;li&gt;✅ No account, no signup, no server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me walk through the things that actually matter when using it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dialect Selection: The Step Everyone Skips
&lt;/h2&gt;

&lt;p&gt;The most important thing to get right before validating is selecting the correct SQL dialect. This isn't optional — it fundamentally changes what's valid.&lt;/p&gt;

&lt;h3&gt;
  
  
  MySQL vs PostgreSQL: The Most Common Confusion
&lt;/h3&gt;

&lt;p&gt;If you work across projects, you've probably written MySQL syntax in a PostgreSQL project (or vice versa) at least once. The errors are subtle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ✅ Valid MySQL&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%keyboard%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- ✅ Valid PostgreSQL (case-insensitive version)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;ILIKE&lt;/span&gt; &lt;span class="s1"&gt;'%keyboard%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- ❌ ILIKE doesn't exist in MySQL — silent failure or error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ✅ Valid MySQL&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- ✅ Valid PostgreSQL equivalent&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- ❌ AUTO_INCREMENT in PostgreSQL → syntax error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you select PostgreSQL in the validator and paste MySQL syntax, these are caught immediately with a clear error message — before you touch a real database.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL Server (T-SQL): A Different World
&lt;/h3&gt;

&lt;p&gt;T-SQL has its own quirks that catch MySQL/PostgreSQL developers off guard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ✅ SQL Server pagination&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;TOP&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- ❌ TOP doesn't exist in MySQL or PostgreSQL&lt;/span&gt;
&lt;span class="c1"&gt;-- They use LIMIT instead&lt;/span&gt;

&lt;span class="c1"&gt;-- ✅ SQL Server OFFSET pagination (SQL Server 2012+)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;OFFSET&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;ROWS&lt;/span&gt; &lt;span class="k"&gt;FETCH&lt;/span&gt; &lt;span class="k"&gt;NEXT&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="k"&gt;ROWS&lt;/span&gt; &lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ✅ SQL Server string search&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;CHARINDEX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'@gmail.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- ✅ PostgreSQL equivalent&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;STRPOS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'@gmail.com'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- These are NOT interchangeable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Selecting the right dialect in the validator means each of these is caught before you push code.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Format + Validate Workflow
&lt;/h2&gt;

&lt;p&gt;One of the most useful features is the Format + Validate button — it reformats your query &lt;em&gt;and&lt;/em&gt; validates it in a single click.&lt;/p&gt;

&lt;p&gt;Here's a realistic example of a query written in a hurry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="k"&gt;left&lt;/span&gt; &lt;span class="k"&gt;join&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'pending'&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt; &lt;span class="k"&gt;limit&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After Format + Validate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;order_id&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'pending'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same query. Immediately readable. And confirmed valid MySQL syntax.&lt;/p&gt;

&lt;p&gt;The formatting rules follow conventions that keep Git diffs clean — leading commas mean adding a column to the &lt;code&gt;SELECT&lt;/code&gt; list touches one line, not two.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Syntax Errors the Validator Catches
&lt;/h2&gt;

&lt;p&gt;These are the errors that waste the most developer time because they're subtle and easy to miss in a code review:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Wrong Clause Order
&lt;/h3&gt;

&lt;p&gt;SQL has a mandatory clause order. This is wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;order_count&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;-- ❌ WHERE must come before GROUP BY&lt;/span&gt;
&lt;span class="k"&gt;HAVING&lt;/span&gt; &lt;span class="n"&gt;order_count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;order_count&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;-- ✅ WHERE before GROUP BY&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;HAVING&lt;/span&gt; &lt;span class="n"&gt;order_count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The validator flags the first version immediately: &lt;em&gt;"Unexpected WHERE after GROUP BY — WHERE clause must precede GROUP BY."&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Unmatched Parentheses in Subqueries
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;created_at&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;SELECT&lt;/span&gt; &lt;span class="k"&gt;MIN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'PK'&lt;/span&gt;
  &lt;span class="c1"&gt;-- ❌ Missing closing parenthesis for the IN subquery&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a long query, this is genuinely hard to spot manually. The database error message usually points to the end of the file, not the opening parenthesis. The validator shows the exact line.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Missing Table Alias on Ambiguous Columns
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;  &lt;span class="c1"&gt;-- ❌ ambiguous: which table's 'id'?&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When both tables have an &lt;code&gt;id&lt;/code&gt; column, this is ambiguous. Should be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Dialect-Specific Function Names
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ❌ NVL doesn't exist in PostgreSQL or MySQL&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;NVL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'N/A'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- ✅ Use COALESCE (works in all four dialects)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'N/A'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Integrating SQL Validation Into Your Actual Workflow
&lt;/h2&gt;

&lt;p&gt;A tool only helps if you actually use it. Here's how I've integrated this into my day-to-day:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before running any migration:&lt;/strong&gt; Every migration script gets pasted into the validator before it runs. This takes 30 seconds and has saved me multiple times. The &lt;a href="https://www.webtoolshub.online/tools/cron-job-generator" rel="noopener noreferrer"&gt;Cron Job Generator&lt;/a&gt; on the same site is useful when those migrations are triggered by scheduled jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;During code review:&lt;/strong&gt; Instead of just reading SQL queries in a PR, I paste each one into the validator. It takes 10 seconds per query and catches things your eyes miss after the third read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When switching dialects:&lt;/strong&gt; Any time I port a query from one database to another, I change the dialect selector and re-validate. Catches &lt;code&gt;AUTO_INCREMENT&lt;/code&gt; vs &lt;code&gt;SERIAL&lt;/code&gt; type issues immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For learning:&lt;/strong&gt; If you're newer to SQL, the error messages are written to explain &lt;em&gt;what&lt;/em&gt; is wrong and &lt;em&gt;why&lt;/em&gt; — not just throw a code at you. Write a query, see what's wrong, fix it, understand it. Faster feedback loop than spinning up a local database.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Privacy Argument for Client-Side Tools
&lt;/h2&gt;

&lt;p&gt;Most online SQL formatters and validators send your queries to a backend server. I'd argue this is a problem people underestimate.&lt;/p&gt;

&lt;p&gt;Your SQL queries contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Table and column names (schema information)&lt;/li&gt;
&lt;li&gt;Sample data values embedded in WHERE clauses&lt;/li&gt;
&lt;li&gt;JOIN conditions that reveal data relationships&lt;/li&gt;
&lt;li&gt;Business logic embedded in complex queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pasting production schema information into a third-party server-side tool is a real data governance question — especially if you're under any kind of compliance requirement (GDPR, SOC 2, HIPAA adjacent work).&lt;/p&gt;

&lt;p&gt;With a client-side validator, the answer to that question is simple: the data never leaves your browser. No logs, no storage, no backend.&lt;/p&gt;

&lt;p&gt;If you're interested in the architecture behind building client-side tools like this, there's a detailed breakdown on WebToolsHub: &lt;a href="https://www.webtoolshub.online/blog/api-cost-trap-client-side-processing-nextjs-webassembly" rel="noopener noreferrer"&gt;Why client-side processing is the right model for developer tools&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Reference: Dialect Differences Cheat Sheet
&lt;/h2&gt;

&lt;p&gt;Bookmark this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;MySQL&lt;/th&gt;
&lt;th&gt;PostgreSQL&lt;/th&gt;
&lt;th&gt;SQLite&lt;/th&gt;
&lt;th&gt;SQL Server&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Auto-increment&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AUTO_INCREMENT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;SERIAL&lt;/code&gt; / &lt;code&gt;GENERATED ALWAYS AS IDENTITY&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;INTEGER PRIMARY KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IDENTITY(1,1)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pagination&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LIMIT x OFFSET y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LIMIT x OFFSET y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LIMIT x OFFSET y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;TOP n&lt;/code&gt; / &lt;code&gt;OFFSET FETCH&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Case-insensitive search&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LIKE&lt;/code&gt; (default)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ILIKE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LIKE&lt;/code&gt; + PRAGMA&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LIKE&lt;/code&gt; (default)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;String position&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LOCATE()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;STRPOS()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;INSTR()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CHARINDEX()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current time&lt;/td&gt;
&lt;td&gt;&lt;code&gt;NOW()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;NOW()&lt;/code&gt; / &lt;code&gt;CURRENT_TIMESTAMP&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;datetime('now')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GETDATE()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Identifier quoting&lt;/td&gt;
&lt;td&gt;Backticks&lt;/td&gt;
&lt;td&gt;Double quotes&lt;/td&gt;
&lt;td&gt;Both&lt;/td&gt;
&lt;td&gt;Square brackets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boolean type&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TINYINT(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BOOLEAN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;INTEGER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BIT&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you're building regex patterns for &lt;code&gt;REGEXP&lt;/code&gt; or &lt;code&gt;SIMILAR TO&lt;/code&gt; clauses, the &lt;a href="https://www.webtoolshub.online/tools/regex-tester-debugger" rel="noopener noreferrer"&gt;Regex Tester&lt;/a&gt; on WebToolsHub lets you test the pattern in isolation before embedding it in SQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'm Working on Next
&lt;/h2&gt;

&lt;p&gt;The SQL Query Validator is live now at &lt;a href="https://www.webtoolshub.online/tools/sql-query-validator" rel="noopener noreferrer"&gt;webtoolshub.online/tools/sql-query-validator&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Coming next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schema-aware validation&lt;/strong&gt; — paste &lt;code&gt;CREATE TABLE&lt;/code&gt; statements alongside your query to catch column-name typos before runtime&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open Graph Preview Tool&lt;/strong&gt; — because broken social share cards are the other category of "should have caught this before deploying"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found this useful, the WebToolsHub blog also covers the full &lt;a href="https://www.webtoolshub.online/blog/cron-job-syntax-complete-guide-2026" rel="noopener noreferrer"&gt;cron job syntax guide for 2026&lt;/a&gt; — useful if your SQL runs in scheduled jobs — and there's a solid breakdown of &lt;a href="https://www.webtoolshub.online/blog/typescript-mistakes-killing-your-nextjs-app" rel="noopener noreferrer"&gt;TypeScript mistakes that kill Next.js performance&lt;/a&gt; if that's your stack.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;🔗 &lt;a href="https://www.webtoolshub.online/tools/sql-query-validator" rel="noopener noreferrer"&gt;SQL Query Validator — Free, browser-based, no signup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's your current SQL validation workflow? Drop it in the comments — I'm genuinely curious whether anyone has a better system than "paste and pray."&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>AWS Kiro IDE: Amazon's Spec-Driven AI Coding Tool Explained (2026 Review)</title>
      <dc:creator>Muhammad Awais</dc:creator>
      <pubDate>Wed, 10 Jun 2026 06:51:38 +0000</pubDate>
      <link>https://dev.to/webtoolshub/aws-kiro-ide-amazons-spec-driven-ai-coding-tool-explained-2026-review-3l67</link>
      <guid>https://dev.to/webtoolshub/aws-kiro-ide-amazons-spec-driven-ai-coding-tool-explained-2026-review-3l67</guid>
      <description>&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%2Fnjr7uoysi4hpkbq7wfyk.webp" 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%2Fnjr7uoysi4hpkbq7wfyk.webp" alt="AWS Kiro IDE: Amazon's Spec-Driven AI Coding Tool Explained (2026 Review)"&gt;&lt;/a&gt;&lt;br&gt;
Amazon made a quiet but significant move on May 7, 2026: &lt;strong&gt;Amazon Q Developer was officially retired&lt;/strong&gt; and replaced with AWS Kiro — a fundamentally different take on AI-assisted development.&lt;/p&gt;

&lt;p&gt;I spent the first week using Kiro on real production work. This is what I found.&lt;/p&gt;


&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Kiro = Amazon's new AI IDE, replaces Q Developer entirely&lt;/li&gt;
&lt;li&gt;Core idea: &lt;strong&gt;spec-driven development&lt;/strong&gt; — AI writes specs &lt;em&gt;before&lt;/em&gt; writing code&lt;/li&gt;
&lt;li&gt;Free tier + $20/mo Pro (same price as Cursor)&lt;/li&gt;
&lt;li&gt;Best for: AWS teams, complex feature development, GovCloud compliance&lt;/li&gt;
&lt;li&gt;Not ideal for: JetBrains/VS users, pure speed-focused workflows, non-AWS stacks&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The Core Concept: Spec-Driven Development
&lt;/h2&gt;

&lt;p&gt;Every other AI coding tool follows the same basic loop: prompt → code → review → iterate.&lt;/p&gt;

&lt;p&gt;Kiro breaks that loop. Instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You describe what you want to build in natural language&lt;/li&gt;
&lt;li&gt;Kiro generates a &lt;strong&gt;structured specification&lt;/strong&gt; — user stories, data models, API contracts, edge cases, dependency list&lt;/li&gt;
&lt;li&gt;You review, edit, and approve the spec&lt;/li&gt;
&lt;li&gt;Only then does code generation begin&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first time I saw this I thought "extra friction." Then I caught an authentication edge case at the spec stage that would have been a subtle production bug two weeks later. That changed my opinion fast.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Traditional AI flow:
prompt("Add JWT auth with refresh tokens") → code → discover edge cases → rework → ...

// Kiro Spec Mode flow:
describe("Add JWT auth with refresh tokens")
→ Kiro generates spec with user stories, data models, error scenarios
→ you spot the edge case in the spec
→ approve → clean code on first generation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Q Developer Migration Timeline
&lt;/h2&gt;

&lt;p&gt;If you're still on Q Developer, here's what matters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;May 7, 2026&lt;/td&gt;
&lt;td&gt;Kiro launches, Q Developer retired&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;May 15, 2026&lt;/td&gt;
&lt;td&gt;New Q Developer sign-ups blocked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;May 29, 2026&lt;/td&gt;
&lt;td&gt;Latest models (Claude Opus 4.7+) exclusive to Kiro&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;April 30, 2027&lt;/td&gt;
&lt;td&gt;Q Developer Pro end of support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The real problem with staying on Q Developer isn't the deadline — it's that you're locked to an older model stack &lt;em&gt;right now&lt;/em&gt;. That gap widens every month.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kiro's Two Modes Explained
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Spec Mode ($0.20/credit)
&lt;/h3&gt;

&lt;p&gt;For complex features. Full spec generation before any code is written. Catches ambiguities at planning stage, not debugging stage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; New features, architectural changes, anything where rework is expensive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vibe Mode ($0.04/credit)
&lt;/h3&gt;

&lt;p&gt;Traditional AI coding flow — prompt, code, iterate. Fast, no overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Quick scripts, prototypes, simple tasks, anything you'd normally tab-complete your way through.&lt;/p&gt;

&lt;p&gt;Most developers split roughly &lt;strong&gt;60% Spec / 40% Vibe&lt;/strong&gt; once they get comfortable with both modes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kiro vs Cursor vs GitHub Copilot
&lt;/h2&gt;

&lt;p&gt;I've written a full &lt;a href="https://www.webtoolshub.online/blog/cursor-vs-windsurf-vs-github-copilot-2026" rel="noopener noreferrer"&gt;Cursor vs Windsurf vs GitHub Copilot comparison&lt;/a&gt; if you want the deep dive, but here's the Kiro-specific breakdown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;AWS Kiro&lt;/th&gt;
&lt;th&gt;Cursor&lt;/th&gt;
&lt;th&gt;GitHub Copilot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Type&lt;/td&gt;
&lt;td&gt;Standalone IDE&lt;/td&gt;
&lt;td&gt;VS Code fork&lt;/td&gt;
&lt;td&gt;Extension&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Philosophy&lt;/td&gt;
&lt;td&gt;Spec-first&lt;/td&gt;
&lt;td&gt;Code-first&lt;/td&gt;
&lt;td&gt;AI-assisted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price&lt;/td&gt;
&lt;td&gt;Free + $20/mo&lt;/td&gt;
&lt;td&gt;Free + $20/mo&lt;/td&gt;
&lt;td&gt;$10/mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tab Completion&lt;/td&gt;
&lt;td&gt;⚠️ Slower&lt;/td&gt;
&lt;td&gt;✅ Best-in-class&lt;/td&gt;
&lt;td&gt;✅ Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex Features&lt;/td&gt;
&lt;td&gt;✅ Spec mode&lt;/td&gt;
&lt;td&gt;✅ Composer&lt;/td&gt;
&lt;td&gt;⚠️ Context limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Native&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;⚠️ GitHub only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open Source&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GovCloud&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The honest version:&lt;/strong&gt; Cursor wins on tab completion speed — Kiro's own supporters admit this. But for complex AWS feature work, Kiro's spec workflow saves time Cursor can't match.&lt;/p&gt;

&lt;p&gt;The emerging pattern in 2026: &lt;strong&gt;Cursor for daily editing, Kiro for complex features, Claude Code for deep terminal reasoning&lt;/strong&gt;. Not replacement — specialization. More on how these tools relate in my &lt;a href="https://www.webtoolshub.online/blog/claude-code-vs-cursor-vs-github-copilot-2026" rel="noopener noreferrer"&gt;Claude Code vs Cursor vs GitHub Copilot 2026&lt;/a&gt; breakdown.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing — Is the Free Tier Enough?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Free tier:&lt;/strong&gt; Enough for genuine evaluation. Not unlimited, but enough to know if the workflow fits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro ($20/month):&lt;/strong&gt; ~225 vibe-mode + 125 spec-mode requests/month.&lt;/p&gt;

&lt;p&gt;That's fewer raw requests than Q Developer's ~1,000/month at the same price. But the math works differently: one spec-mode session building a complex feature can replace 15–20 vibe-mode iterations. Quality per credit is higher, raw volume is lower.&lt;/p&gt;

&lt;p&gt;For enterprise: &lt;strong&gt;GovCloud support&lt;/strong&gt; is a genuine differentiator. If your org has compliance requirements that block standard cloud tools, Kiro clears that bar. Cursor and Copilot don't.&lt;/p&gt;




&lt;h2&gt;
  
  
  Agent Hooks — Kiro's Most Underrated Feature
&lt;/h2&gt;

&lt;p&gt;Agent Hooks let you define automation triggers inside your development workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example: auto type-check on save&lt;/span&gt;
&lt;span class="na"&gt;on_save&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tsc --noEmit&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;notify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Type&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;errors&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;found"&lt;/span&gt; &lt;span class="s"&gt;if exit_code != &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;

&lt;span class="c1"&gt;# Example: auto-generate docs on PR create&lt;/span&gt;
&lt;span class="na"&gt;on_pr_create&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kiro doc-gen ./src&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;commit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docs:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;auto-generated&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;PR"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With native AWS integration, this gets powerful — Lambda updates, CloudFormation changes, and serverless deployments can hook directly into your coding workflow. This is the feature that makes "native AWS IDE" mean something real rather than just marketing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Setup Guide
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Download from kiro.dev (Windows/macOS/Linux)&lt;/span&gt;
&lt;span class="c"&gt;# 2. Connect AWS account or create Kiro account&lt;/span&gt;
&lt;span class="c"&gt;# 3. Import VS Code profile on first launch (~80% transfers cleanly)&lt;/span&gt;
&lt;span class="c"&gt;# 4. Open project — Kiro scans and builds context automatically&lt;/span&gt;
&lt;span class="c"&gt;# 5. Try first spec: Command Palette → "New Spec"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;JetBrains:&lt;/strong&gt; CLI-based ACP integration available, no native plugin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Studio / Eclipse:&lt;/strong&gt; No native support. This is a real blocker, worth knowing before planning a migration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser-based tools&lt;/strong&gt; stay useful alongside any IDE regardless of environment — I use &lt;a href="https://www.webtoolshub.online/tools/jwt-decoder-verifier" rel="noopener noreferrer"&gt;JWT Decoder &amp;amp; Verifier&lt;/a&gt;, &lt;a href="https://www.webtoolshub.online/tools/regex-tester-debugger" rel="noopener noreferrer"&gt;Regex Tester&lt;/a&gt;, &lt;a href="https://www.webtoolshub.online/tools/unix-timestamp-converter" rel="noopener noreferrer"&gt;Unix Timestamp Converter&lt;/a&gt;, and &lt;a href="https://www.webtoolshub.online/tools/jwt-secret-key-generator" rel="noopener noreferrer"&gt;JWT Secret Key Generator&lt;/a&gt; as IDE-independent companions throughout.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who Should Actually Switch?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Switch if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You're on Q Developer (migration is inevitable, sooner is better given the model gap)&lt;/li&gt;
&lt;li&gt;You work with AWS regularly (Lambda, Bedrock, ECS, RDS, CloudFormation)&lt;/li&gt;
&lt;li&gt;You build complex features where spec-driven planning reduces rework&lt;/li&gt;
&lt;li&gt;GovCloud compliance is a requirement&lt;/li&gt;
&lt;li&gt;Open-source tooling matters to your team&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚠️ Hold off if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Your IDE is JetBrains, Visual Studio, or Eclipse — native support isn't there yet&lt;/li&gt;
&lt;li&gt;Tab completion speed is your primary metric&lt;/li&gt;
&lt;li&gt;Your stack is primarily GCP or Azure&lt;/li&gt;
&lt;li&gt;You're solo and mostly prototyping — Cursor or Vibe Mode alone serves that better&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Broader Context: Why This Approach Is Gaining Ground
&lt;/h2&gt;

&lt;p&gt;Kiro isn't just a new tool — it's a bet on &lt;strong&gt;agentic development&lt;/strong&gt; becoming the professional default. Gartner tracked a 1,445% surge in multi-agent system inquiries between Q1 2024 and Q2 2025.&lt;/p&gt;

&lt;p&gt;I've written about where this is heading in &lt;a href="https://www.webtoolshub.online/blog/guide-to-autonomous-ai-agents-agentic-workflows" rel="noopener noreferrer"&gt;Autonomous AI Agents and Agentic Workflows&lt;/a&gt;, and about &lt;a href="https://www.webtoolshub.online/blog/vibe-coding-complete-guide-2026" rel="noopener noreferrer"&gt;vibe coding as a philosophy&lt;/a&gt; — both connect to what Kiro is building toward. The &lt;a href="https://www.webtoolshub.online/blog/google-io-2026-developer-announcements" rel="noopener noreferrer"&gt;Google I/O 2026 announcements&lt;/a&gt; also showed how the broader industry is moving in this direction.&lt;/p&gt;

&lt;p&gt;Amazon's logic is clear: they have the model infrastructure on Bedrock. Kiro is the developer-facing interface that routes that infrastructure directly into coding workflows. If agentic development becomes the professional default — and the trend lines point that way — Kiro is positioned ahead of most competitors.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;For AWS developers building complex features: &lt;strong&gt;worth it, with real evidence behind that claim&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For everyone else: no urgent reason to switch your full setup. But trying Spec Mode on one real feature you're planning to build — that 15-minute experiment will tell you more than any review, including this one.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Are you on Q Developer or have you already migrated? What's your experience with spec-driven development? Drop a comment — genuinely curious how different teams are handling this.&lt;/em&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Awais&lt;/strong&gt; is a developer and builder behind &lt;a href="https://www.webtoolshub.online" rel="noopener noreferrer"&gt;WebToolsHub&lt;/a&gt; — a growing collection of free browser-based tools for developers. No sign-up, no server-side data processing, just tools that work.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
