<?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: The Agent Ledger</title>
    <description>The latest articles on DEV Community by The Agent Ledger (@theagentledger).</description>
    <link>https://dev.to/theagentledger</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%2F4195188%2F188ef493-49b6-4c77-a52d-32d9aac6fcc1.png</url>
      <title>DEV Community: The Agent Ledger</title>
      <link>https://dev.to/theagentledger</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theagentledger"/>
    <language>en</language>
    <item>
      <title>Fixing "Hydration failed because the server rendered text didn't match the client" from dates in Next.js (tested repro, Next 16 + React 19.3)</title>
      <dc:creator>The Agent Ledger</dc:creator>
      <pubDate>Wed, 21 Oct 2026 01:59:40 +0000</pubDate>
      <link>https://dev.to/theagentledger/fixing-hydration-failed-because-the-server-rendered-text-didnt-match-the-client-from-dates-in-4bl</link>
      <guid>https://dev.to/theagentledger/fixing-hydration-failed-because-the-server-rendered-text-didnt-match-the-client-from-dates-in-4bl</guid>
      <description>&lt;p&gt;If your AI-built (or hand-built) Next.js app throws &lt;code&gt;Hydration failed because the server rendered text didn't match the client&lt;/code&gt; in the browser, a common culprit is a date formatted with &lt;code&gt;toLocaleDateString()&lt;/code&gt; or &lt;code&gt;toLocaleString()&lt;/code&gt; and no locale or time zone. The server and your visitor's browser print different text, and React refuses to hydrate.&lt;/p&gt;

&lt;p&gt;We reproduced it on a small synthetic app, applied the smallest fix, and checked it in headless Chrome set to a different locale and time zone than the server. Below: the exact error, the cause, the fix, how we verified it, and what we did &lt;strong&gt;not&lt;/strong&gt; test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The exact error
&lt;/h2&gt;

&lt;p&gt;In development (&lt;code&gt;next dev&lt;/code&gt;), from our headless-browser run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hydration failed because the server rendered text didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:

- A server/client branch `if (typeof window !== 'undefined')`.
- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
- Date formatting in a user's locale which doesn't match the server.
...
&amp;lt;time id="placed" dateTime="2026-01-13T23:30:00Z"&amp;gt;
+  14.1.2026
-  1/13/2026
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;+&lt;/code&gt; line is what the browser rendered; the &lt;code&gt;-&lt;/code&gt; line is what the server sent.&lt;/p&gt;

&lt;p&gt;In production (&lt;code&gt;next build&lt;/code&gt; + &lt;code&gt;next start&lt;/code&gt;) the same problem shows only as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Minified React error #418; visit https://react.dev/errors/418?args[]=text&amp;amp;args[]= for the full message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Older React/Next versions word this differently, for example "Text content does not match server-rendered HTML" (the title of the &lt;a href="https://nextjs.org/docs/messages/react-hydration-error" rel="noopener noreferrer"&gt;official Next.js page&lt;/a&gt;). We did not run those versions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versions we used
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;20.19.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;next&lt;/td&gt;
&lt;td&gt;16.4.2 (Turbopack)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;react / react-dom&lt;/td&gt;
&lt;td&gt;19.3.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser&lt;/td&gt;
&lt;td&gt;Google Chrome, headless, via playwright-core 1.64.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server time zone&lt;/td&gt;
&lt;td&gt;UTC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser locale / time zone&lt;/td&gt;
&lt;td&gt;de-DE / Europe/Berlin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OS&lt;/td&gt;
&lt;td&gt;Linux, single machine&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Cause
&lt;/h2&gt;

&lt;p&gt;Even a &lt;code&gt;"use client"&lt;/code&gt; component is rendered twice: once on the server to make the HTML, and again in the browser to make it interactive ("hydration"). React requires the two results to match.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;new Date(x).toLocaleDateString()&lt;/code&gt; with no arguments uses whatever locale and time zone the current machine has. Our server was in UTC with US English, so it printed &lt;code&gt;1/13/2026&lt;/code&gt;. The browser was in Berlin with German, where the same moment (&lt;code&gt;2026-01-13T23:30:00Z&lt;/code&gt;) is already 14 January, so it printed &lt;code&gt;14.1.2026&lt;/code&gt;. Same code, two answers, hydration error.&lt;/p&gt;

&lt;p&gt;The same thing happens with &lt;code&gt;Date.now()&lt;/code&gt;, &lt;code&gt;new Date()&lt;/code&gt;, &lt;code&gt;Math.random()&lt;/code&gt;, or &lt;code&gt;typeof window&lt;/code&gt; checks used during render. We reproduced only the locale/time-zone date case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smallest working fix
&lt;/h2&gt;

&lt;p&gt;Pass an explicit locale &lt;strong&gt;and&lt;/strong&gt; time zone, so the server and every browser format the date identically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before (hydration error): &lt;code&gt;app/OrderRow.js&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="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;OrderRow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createdAt&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setOpen&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Order&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;placed&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;placed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;dateTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;createdAt&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;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;createdAt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/time&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hide&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="s2"&gt;Details&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;details&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Synthetic&lt;/span&gt; &lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After (no hydration error)
&lt;/h3&gt;

&lt;p&gt;Change the &lt;code&gt;&amp;lt;time&amp;gt;&lt;/code&gt; line to call &lt;code&gt;formatDate(createdAt)&lt;/code&gt; and add this at the bottom of the file:&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;// Same locale and time zone on the server and in every browser,&lt;/span&gt;
&lt;span class="c1"&gt;// so the first browser render matches the server HTML.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iso&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iso&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UTC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pick the locale and zone that fit your business (for example &lt;code&gt;"en-US"&lt;/code&gt; and &lt;code&gt;"America/Phoenix"&lt;/code&gt;). The trade-off: every visitor sees that same zone's date. If you need each visitor's own local date, the usual pattern is to render a neutral value first and switch to local formatting in &lt;code&gt;useEffect&lt;/code&gt; after hydration. That is documented on the &lt;a href="https://nextjs.org/docs/messages/react-hydration-error" rel="noopener noreferrer"&gt;Next.js hydration page&lt;/a&gt;, but &lt;strong&gt;we did not test that variant.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt for your AI coding tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My Next.js App Router app shows "Hydration failed because the server rendered text didn't match the client" in the browser console. Find every place that formats dates, times, numbers or prices during render using toLocaleString, toLocaleDateString, toLocaleTimeString or Intl.DateTimeFormat/Intl.NumberFormat without an explicit locale and timeZone, and every place that uses Date.now(), new Date() with no argument, or Math.random() during render. For the formatting cases, pass an explicit locale and timeZone (use "en-US" and "UTC" unless I tell you otherwise). For the clock/random cases, compute the value on the server and pass it as a prop, or set it in useEffect. Do not change anything else, and show me the diff.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Review the diff yourself. We did not test this prompt in any AI tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we verified
&lt;/h2&gt;

&lt;p&gt;All runs on 2026-10-20 on a small synthetic app. Server started with &lt;code&gt;TZ=UTC&lt;/code&gt;; headless Chrome set to locale &lt;code&gt;de-DE&lt;/code&gt; and time zone &lt;code&gt;Europe/Berlin&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Both builds pass:&lt;/strong&gt; &lt;code&gt;npx next build&lt;/code&gt; exited 0 for before and after. The bug does not show at build time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Before, production (&lt;code&gt;next start&lt;/code&gt;):&lt;/strong&gt; the browser threw &lt;code&gt;Minified React error #418 ... args[]=text&lt;/code&gt;. Server HTML had &lt;code&gt;1/13/2026&lt;/code&gt;; after hydration the page showed &lt;code&gt;14.1.2026&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Before, dev (&lt;code&gt;next dev&lt;/code&gt;):&lt;/strong&gt; the browser threw the full "Hydration failed ..." message with the &lt;code&gt;+ 14.1.2026 / - 1/13/2026&lt;/code&gt; diff shown above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After, production and dev:&lt;/strong&gt; no hydration error or React error in the console; server HTML and the hydrated page both showed &lt;code&gt;1/13/2026&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Button still works:&lt;/strong&gt; in every run, clicking "Details" showed the details paragraph.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both runs also logged one unrelated &lt;code&gt;404&lt;/code&gt; resource error, most likely the missing favicon; we did not confirm which file it was.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not verified
&lt;/h2&gt;

&lt;p&gt;To be upfront about the limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Other browsers (Firefox, Safari), real phones, and real visitors' settings; we simulated one locale/time zone in headless Chrome.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;useEffect&lt;/code&gt; "show local time after load" variant.&lt;/li&gt;
&lt;li&gt;The other causes in the error message (&lt;code&gt;Date.now()&lt;/code&gt;, &lt;code&gt;Math.random()&lt;/code&gt;, &lt;code&gt;typeof window&lt;/code&gt;, invalid HTML nesting, browser extensions). Same family, not reproduced.&lt;/li&gt;
&lt;li&gt;Other Next.js/React/Node versions, including older "Text content does not match" wording, and the Pages Router.&lt;/li&gt;
&lt;li&gt;Vercel, Netlify, Cloudflare or other hosts (host server time zones may differ from ours).&lt;/li&gt;
&lt;li&gt;Code generated by Cursor, Lovable, Bolt or v0; our app is hand-written and synthetic. We did not measure how often AI tools produce this pattern.&lt;/li&gt;
&lt;li&gt;Whether the AI prompt produces a correct diff in any tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick troubleshooting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Only see "Minified React error #418":&lt;/strong&gt; run &lt;code&gt;npm run dev&lt;/code&gt; and open the page; the dev overlay shows the full message with the &lt;code&gt;+&lt;/code&gt;/&lt;code&gt;-&lt;/code&gt; diff that points to the exact text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error goes away on your machine but users report it:&lt;/strong&gt; your computer and server may share a time zone. Test with a browser set to a different time zone or language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The diff points to an attribute, not text, or you have a password manager/translate extension:&lt;/strong&gt; try a private window with extensions off; extensions can cause this too (not tested by us).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prices like &lt;code&gt;1,234.50&lt;/code&gt; vs &lt;code&gt;1.234,50&lt;/code&gt;:&lt;/strong&gt; same cause; pass a locale to &lt;code&gt;toLocaleString&lt;/code&gt; / &lt;code&gt;Intl.NumberFormat&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security: no secrets are involved. Don't "fix" this by disabling server rendering for whole pages without understanding the SEO and performance cost.&lt;/p&gt;




&lt;p&gt;The original guide, with the before/after files, is on The Agent Ledger: &lt;a href="https://theagentledger.ai/fixes/hydration-mismatch-date-locale/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=fix03" rel="noopener noreferrer"&gt;Hydration mismatch from date locale: Next.js fix&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI disclosure: This article was written with the help of AI. The reproduction and the before/after browser runs described above were actually performed and checked against the logs before publishing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>Fixing "supabaseUrl is required" when next build fails (tested repro, Next 16 + supabase-js 2.109)</title>
      <dc:creator>The Agent Ledger</dc:creator>
      <pubDate>Tue, 20 Oct 2026 02:46:29 +0000</pubDate>
      <link>https://dev.to/theagentledger/fixing-supabaseurl-is-required-when-next-build-fails-tested-repro-next-16-supabase-js-2109-17bp</link>
      <guid>https://dev.to/theagentledger/fixing-supabaseurl-is-required-when-next-build-fails-tested-repro-next-16-supabase-js-2109-17bp</guid>
      <description>&lt;p&gt;If your AI-built (or hand-built) Next.js app dies during &lt;code&gt;next build&lt;/code&gt; with &lt;code&gt;Error: supabaseUrl is required.&lt;/code&gt;, the usual culprit is one line: a Supabase client created at the &lt;strong&gt;top level&lt;/strong&gt; of a route file, evaluated at build time when your env vars aren't there.&lt;/p&gt;

&lt;p&gt;We reproduced it on a small synthetic app, applied the smallest fix, and confirmed the build went from failing to passing. Below: the exact error, the cause, the fix, how we verified it, and what we did &lt;strong&gt;not&lt;/strong&gt; test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The exact error
&lt;/h2&gt;

&lt;p&gt;From our reproduction (&lt;code&gt;npx next build&lt;/code&gt;, no &lt;code&gt;.env&lt;/code&gt; file, no Supabase vars set):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Collecting page data using 5 workers ...
Error: Failed to collect configuration for /api/waitlist
    at ignore-listed frames {
  [cause]: Error: supabaseUrl is required.
      at module evaluation (app/api/waitlist/route.js:3:7)
  &amp;gt; 3 | const supabase = createClient(
...
&amp;gt; Build error occurred
Error: Failed to collect page data for /api/waitlist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exit code 1. The same text shows up in public reports, e.g. &lt;a href="https://github.com/vercel/next.js/issues/69095" rel="noopener noreferrer"&gt;vercel/next.js#69095&lt;/a&gt; (Vercel build, Next 14.2.3).&lt;/p&gt;

&lt;h2&gt;
  
  
  Versions we used
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;20.19.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;11.21.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;next&lt;/td&gt;
&lt;td&gt;16.4.2 (Turbopack build)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;react&lt;/td&gt;
&lt;td&gt;19.3.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@supabase/supabase-js&lt;/td&gt;
&lt;td&gt;2.109.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OS&lt;/td&gt;
&lt;td&gt;Linux, single machine&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Cause
&lt;/h2&gt;

&lt;p&gt;During &lt;code&gt;next build&lt;/code&gt;, Next.js loads your route modules to collect page data. If a route file does this at module scope:&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;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&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;NEXT_PUBLIC_SUPABASE_URL&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;NEXT_PUBLIC_SUPABASE_ANON_KEY&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…then &lt;code&gt;createClient&lt;/code&gt; runs during the build. If the variable is missing in the build environment (not in &lt;code&gt;.env.local&lt;/code&gt;, not set on the host, misspelled, or scoped only to Production while you're building a Preview), &lt;code&gt;createClient&lt;/code&gt; throws and the whole build fails. AI coding tools generate this top-level pattern a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smallest working fix
&lt;/h2&gt;

&lt;p&gt;Create the client inside a function and call it in the handler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (fails):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@supabase/supabase-js&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;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&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;NEXT_PUBLIC_SUPABASE_URL&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;NEXT_PUBLIC_SUPABASE_ANON_KEY&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;waitlist&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;insert&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (builds):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@supabase/supabase-js&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;getSupabase&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_SUPABASE_URL&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;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_SUPABASE_ANON_KEY&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;url&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;key&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="s2"&gt;Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY&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="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="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="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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getSupabase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;waitlist&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;insert&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="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;e&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;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use an AI coding tool, a prompt like this describes the change (we did &lt;strong&gt;not&lt;/strong&gt; test the prompt in any tool; review the diff yourself):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My Next.js build fails with "Error: supabaseUrl is required." Find every file that calls createClient from @supabase/supabase-js at the top level of a module. Move each call into a getSupabase() function that reads process.env at request time and throws a clear error naming the missing variable. Don't rename variables, don't print key values, don't change anything else. Show me the diff.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How we verified it
&lt;/h2&gt;

&lt;p&gt;All runs on 2026-10-18, no &lt;code&gt;.env&lt;/code&gt; file, no Supabase variables set:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Before:&lt;/strong&gt; &lt;code&gt;npx next build&lt;/code&gt; → failed with the error above, exit code 1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After:&lt;/strong&gt; &lt;code&gt;npx next build&lt;/code&gt; → exit code 0; output listed &lt;code&gt;ƒ /api/waitlist&lt;/code&gt; as a dynamic route.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After, runtime with missing keys:&lt;/strong&gt; &lt;code&gt;npx next start&lt;/code&gt;, then &lt;code&gt;POST /api/waitlist&lt;/code&gt; with a fake email → &lt;code&gt;HTTP/1.1 500&lt;/code&gt; and &lt;code&gt;{"ok":false,"error":"Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY"}&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What the fix does not do:&lt;/strong&gt; it doesn't supply your keys. It makes the build pass and moves the failure to a clear, request-time error. If your deployed app needs Supabase, you still have to set the variables on your host. &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; values are inlined at build time, so redeploy after changing them (documented Next.js behavior; not re-tested here).&lt;/p&gt;

&lt;h2&gt;
  
  
  Not verified
&lt;/h2&gt;

&lt;p&gt;To be upfront about the limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No real Supabase project: we never made a successful insert or any network call to Supabase.&lt;/li&gt;
&lt;li&gt;No Vercel, Netlify or other host build environment.&lt;/li&gt;
&lt;li&gt;No Lovable, Bolt, Cursor or v0 output. Our app is hand-written and synthetic, modeled on the pattern in public reports.&lt;/li&gt;
&lt;li&gt;No other versions (including Next 14), the Pages Router, or Vite/React apps.&lt;/li&gt;
&lt;li&gt;The AI prompt above was not run in any tool.&lt;/li&gt;
&lt;li&gt;The "placeholder env vars in CI" workaround was not tested.&lt;/li&gt;
&lt;li&gt;Other causes with the same symptom (misspelled or un-prefixed variable names, missing &lt;code&gt;.env.local&lt;/code&gt;) were not reproduced.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick troubleshooting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build passes, live app returns "Missing NEXT_PUBLIC_SUPABASE_URL…"&lt;/strong&gt;: set the variable on your host with the exact name, then redeploy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Same build error after the fix&lt;/strong&gt;: another file still creates a client at the top level. Search for &lt;code&gt;createClient(&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works locally, fails on host&lt;/strong&gt;: &lt;code&gt;.env.local&lt;/code&gt; usually isn't committed, so the host never sees it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security: never put a service-role key in a &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; variable, since it ships to every browser. And don't paste real keys into AI chats or issues.&lt;/p&gt;




&lt;p&gt;The original guide, with the before/after files, is on The Agent Ledger: &lt;a href="https://theagentledger.ai/fixes/supabaseurl-is-required-next-build/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=fix01" rel="noopener noreferrer"&gt;supabaseUrl is required: next build fix&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI disclosure: This article was written with the help of AI. The reproduction and the before/after build runs described above were actually performed and checked against the logs before publishing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>supabase</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
