<?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: 𝗝𝗼𝗵𝗻</title>
    <description>The latest articles on DEV Community by 𝗝𝗼𝗵𝗻 (@johnnylemonny).</description>
    <link>https://dev.to/johnnylemonny</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%2F3868757%2F52777a3a-3f32-4bcd-8f3c-002c1983dcac.jpg</url>
      <title>DEV Community: 𝗝𝗼𝗵𝗻</title>
      <link>https://dev.to/johnnylemonny</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/johnnylemonny"/>
    <language>en</language>
    <item>
      <title>7 New JavaScript Features in ECMAScript 2026 That Replace Everyday Workarounds</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Tue, 14 Jul 2026 12:20:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/7-new-javascript-features-in-ecmascript-2026-that-replace-everyday-workarounds-2076</link>
      <guid>https://dev.to/johnnylemonny/7-new-javascript-features-in-ecmascript-2026-that-replace-everyday-workarounds-2076</guid>
      <description>&lt;p&gt;JavaScript receives a new specification every year, but not every release changes the way we write everyday application code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ECMAScript 2026 is different.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The 17th edition of the ECMAScript specification was approved by Ecma International on June 30, 2026. It introduces several small but highly practical APIs that replace patterns many of us have been writing manually for years.&lt;/p&gt;

&lt;p&gt;No new framework is required. No architectural rewrite is necessary. These are language-level improvements for frontend applications, Node.js services, libraries, APIs, data pipelines, and developer tools.&lt;/p&gt;

&lt;p&gt;In this article, we will explore seven additions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Array.fromAsync()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Map.prototype.getOrInsert()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Iterator.concat()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Error.isError()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Math.sumPrecise()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Native Base64 and hex support for &lt;code&gt;Uint8Array&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;JSON source text access and raw JSON&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let us look at the problems they solve and where they can be useful in real projects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before using a new API in production, check support in your target browsers and JavaScript runtimes. Feature detection, progressive enhancement, or a compatible fallback may still be appropriate.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. Convert async data into an array with &lt;code&gt;Array.fromAsync()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;JavaScript has supported &lt;code&gt;Array.from()&lt;/code&gt; for synchronous iterables for years.&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;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&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="mi"&gt;3&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;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// [1, 2, 3]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, &lt;code&gt;Array.from()&lt;/code&gt; cannot consume an asynchronous iterable.&lt;/p&gt;

&lt;p&gt;Until now, collecting values from an async generator usually required a manual loop:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;loadPages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchPage&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;yield&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&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;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &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;page&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;loadPages&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With ECMAScript 2026, we can express the same intention more 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;loadPages&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Array.fromAsync()&lt;/code&gt; can also apply a mapping function while collecting the values:&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;titles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;loadPages&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simplified full-stack example could collect results from a paginated API:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;fetchAllUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&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/users?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;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="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;user&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextPage&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;}&lt;/span&gt;

    &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextPage&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;activeUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;fetchAllUsers&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastSeenAt&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;This is useful when working with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;paginated API responses,&lt;/li&gt;
&lt;li&gt;database cursors,&lt;/li&gt;
&lt;li&gt;asynchronous generators,&lt;/li&gt;
&lt;li&gt;streamed records,&lt;/li&gt;
&lt;li&gt;file-processing pipelines,&lt;/li&gt;
&lt;li&gt;values that resolve asynchronously.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main benefit is readability. The code clearly says: &lt;strong&gt;consume this asynchronous source and return an array&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  One important consideration
&lt;/h3&gt;

&lt;p&gt;An array keeps every collected item in memory. If the source can produce a very large or unlimited number of values, process items incrementally with &lt;code&gt;for await...of&lt;/code&gt; instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Initialize Map values with &lt;code&gt;getOrInsert()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;A common &lt;code&gt;Map&lt;/code&gt; pattern is to check whether a value exists, create it if necessary, and then retrieve it.&lt;/p&gt;

&lt;p&gt;For example, grouping products by category often looks like this:&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;productsByCategory&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;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;products&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;productsByCategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;productsByCategory&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="nx"&gt;product&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="p"&gt;[]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;productsByCategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&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;ECMAScript 2026 adds &lt;code&gt;Map.prototype.getOrInsert()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productsByCategory&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;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;productsByCategory&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&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="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the key exists, the method returns the current value. If it does not exist, the provided default is inserted and returned.&lt;/p&gt;

&lt;p&gt;There is also &lt;code&gt;getOrInsertComputed()&lt;/code&gt;, which calculates the value only when a key is missing:&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;userCache&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;Map&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;getUserProfile&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;userCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrInsertComputed&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="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createUserProfile&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="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is especially useful when creating the default value is expensive.&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;reportCache&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;Map&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;getReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectId&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;reportCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrInsertComputed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;createdAt&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="na"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;buildInitialReportRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectId&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;Equivalent methods are also available for &lt;code&gt;WeakMap&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;These methods make several common patterns more concise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;grouping API results,&lt;/li&gt;
&lt;li&gt;memoization,&lt;/li&gt;
&lt;li&gt;per-request caches,&lt;/li&gt;
&lt;li&gt;dependency containers,&lt;/li&gt;
&lt;li&gt;graph construction,&lt;/li&gt;
&lt;li&gt;counters and indexes,&lt;/li&gt;
&lt;li&gt;metadata associated with objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They also communicate intent better than separate &lt;code&gt;has()&lt;/code&gt;, &lt;code&gt;set()&lt;/code&gt;, and &lt;code&gt;get()&lt;/code&gt; calls.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Combine lazy sequences with &lt;code&gt;Iterator.concat()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Suppose an application receives items from multiple sources:&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;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;localArticles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;local&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;local&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;partnerArticles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;partner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;partner&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;Previously, we might have created an array:&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;articles&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="nf"&gt;localArticles&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;partnerArticles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This immediately consumes both iterators and stores all their values in memory.&lt;/p&gt;

&lt;p&gt;ECMAScript 2026 provides &lt;code&gt;Iterator.concat()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;localArticles&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nf"&gt;partnerArticles&lt;/span&gt;&lt;span class="p"&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="nx"&gt;article&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;articles&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;article&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 combined iterator remains lazy. Values are requested only when the consumer needs them.&lt;/p&gt;

&lt;p&gt;It can also combine arrays and other synchronous iterables:&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;navigationItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&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="s2"&gt;Home&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;Articles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nf"&gt;getProjectLinks&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="s2"&gt;Settings&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;h3&gt;
  
  
  Why laziness is useful
&lt;/h3&gt;

&lt;p&gt;Lazy iteration can help when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inputs are large,&lt;/li&gt;
&lt;li&gt;producing an item requires computation,&lt;/li&gt;
&lt;li&gt;the consumer may stop early,&lt;/li&gt;
&lt;li&gt;allocating an intermediate array is unnecessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&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;allCandidates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;getPrimaryCandidates&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nf"&gt;getFallbackCandidates&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nf"&gt;getArchivedCandidates&lt;/span&gt;&lt;span class="p"&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="nx"&gt;candidate&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;allCandidates&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;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matches&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="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="s2"&gt;Found:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;break&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 later sources may never be evaluated if an earlier match is found.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Detect genuine Error objects with &lt;code&gt;Error.isError()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Most JavaScript developers use &lt;code&gt;instanceof&lt;/code&gt; to determine whether a caught value is an error:&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveDocument&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;value&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;value&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works in many applications, but it can be unreliable when the error comes from a different JavaScript realm, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an iframe,&lt;/li&gt;
&lt;li&gt;another browser window,&lt;/li&gt;
&lt;li&gt;certain VM environments,&lt;/li&gt;
&lt;li&gt;isolated execution contexts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each realm can have a different &lt;code&gt;Error&lt;/code&gt; constructor. An error created elsewhere may therefore fail the local &lt;code&gt;instanceof Error&lt;/code&gt; check.&lt;/p&gt;

&lt;p&gt;ECMAScript 2026 introduces &lt;code&gt;Error.isError()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveDocument&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;value&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="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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="k"&gt;else&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="s2"&gt;A non-Error value was thrown:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&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;A reusable normalization helper becomes straightforward:&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;function&lt;/span&gt; &lt;span class="nf"&gt;normalizeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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;value&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&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="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="nx"&gt;value&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;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;An unknown error occurred&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;cause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&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;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;This API is particularly useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;component libraries,&lt;/li&gt;
&lt;li&gt;iframe-based applications,&lt;/li&gt;
&lt;li&gt;plugin systems,&lt;/li&gt;
&lt;li&gt;test runners,&lt;/li&gt;
&lt;li&gt;browser automation,&lt;/li&gt;
&lt;li&gt;sandboxed code,&lt;/li&gt;
&lt;li&gt;error-monitoring SDKs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It gives the language a direct and explicit way to answer a surprisingly difficult question: &lt;strong&gt;is this value actually an Error object?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Sum floating-point values more accurately with &lt;code&gt;Math.sumPrecise()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Floating-point arithmetic can lose precision, especially when values with very different magnitudes are added sequentially.&lt;/p&gt;

&lt;p&gt;Consider this calculation:&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;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e16&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;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&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;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="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;total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Commonly 0, although the mathematical result is 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The small &lt;code&gt;1&lt;/code&gt; can disappear during intermediate floating-point operations.&lt;/p&gt;

&lt;p&gt;ECMAScript 2026 adds &lt;code&gt;Math.sumPrecise()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&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;sumPrecise&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e16&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;total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It accepts an iterable, so it can also work with data transformations:&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;completedOrderValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&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;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&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;total&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;revenue&lt;/span&gt; &lt;span class="o"&gt;=&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;sumPrecise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;completedOrderValues&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with a generator:&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;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;validMeasurements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&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="nx"&gt;row&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;rows&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="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;measurement&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;measurement&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&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;sumPrecise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;validMeasurements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataset&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;
  
  
  Important: this is not decimal arithmetic
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Math.sumPrecise()&lt;/code&gt; reduces floating-point accumulation error, but JavaScript numbers are still IEEE 754 floating-point values.&lt;/p&gt;

&lt;p&gt;For money, the safest approach is usually to store minor units as integers:&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;pricesInCents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;349&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;totalInCents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pricesInCents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&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;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;Math.sumPrecise()&lt;/code&gt; when you intentionally work with floating-point measurements, statistics, coordinates, scientific data, or mixed-magnitude values.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Encode and decode binary data without custom Base64 helpers
&lt;/h2&gt;

&lt;p&gt;Web applications frequently need to convert binary data to Base64 or hexadecimal strings.&lt;/p&gt;

&lt;p&gt;Common use cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API payloads,&lt;/li&gt;
&lt;li&gt;cryptographic data,&lt;/li&gt;
&lt;li&gt;file chunks,&lt;/li&gt;
&lt;li&gt;content hashes,&lt;/li&gt;
&lt;li&gt;authentication challenges,&lt;/li&gt;
&lt;li&gt;browser storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Historically, developers often combined &lt;code&gt;btoa()&lt;/code&gt;, &lt;code&gt;atob()&lt;/code&gt;, loops, buffers, or third-party helpers. Those approaches could be awkward, environment-specific, or unsafe for arbitrary binary data.&lt;/p&gt;

&lt;p&gt;ECMAScript 2026 adds dedicated methods to &lt;code&gt;Uint8Array&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Base64
&lt;/h3&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;bytes&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;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;108&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;108&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;111&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;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBase64&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;encoded&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// SGVsbG8=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Decode it again:&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;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromBase64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SGVsbG8=&lt;/span&gt;&lt;span class="dl"&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;decoded&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Uint8Array(5) [72, 101, 108, 108, 111]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hexadecimal
&lt;/h3&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;token&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;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;160&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="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;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toHex&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="c1"&gt;// 0fa0ff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in the opposite direction:&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;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0fa0ff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A digest helper can now be written cleanly:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createSha256Hex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&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;TextEncoder&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="nx"&gt;input&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;digest&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;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SHA-256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;source&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;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHex&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;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;These methods create a clearer, standardized path for binary conversion across JavaScript environments.&lt;/p&gt;

&lt;p&gt;The code is easier to review because developers no longer need to recognize a custom chain of character conversions as “binary data to Base64.”&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Preserve important JSON source information
&lt;/h2&gt;

&lt;p&gt;JSON numbers are parsed into JavaScript &lt;code&gt;Number&lt;/code&gt; values. This can cause information loss when the source contains an integer larger than JavaScript can represent safely.&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;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"transactionId":123456789012345678901234567890}&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;result&lt;/span&gt; &lt;span class="o"&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;parse&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;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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// The original integer may already have lost precision&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ECMAScript 2026 extends the &lt;code&gt;JSON.parse()&lt;/code&gt; reviver with access to the original source text.&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;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"transactionId":123456789012345678901234567890}&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;result&lt;/span&gt; &lt;span class="o"&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;parse&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="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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&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="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transactionId&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="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&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;value&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="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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// 123456789012345678901234567890n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key detail is &lt;code&gt;context.source&lt;/code&gt;. It shows the matched JSON source before the already-parsed &lt;code&gt;Number&lt;/code&gt; value becomes the only available representation.&lt;/p&gt;

&lt;p&gt;This is useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;database identifiers,&lt;/li&gt;
&lt;li&gt;blockchain values,&lt;/li&gt;
&lt;li&gt;high-precision API data,&lt;/li&gt;
&lt;li&gt;large counters,&lt;/li&gt;
&lt;li&gt;scientific datasets,&lt;/li&gt;
&lt;li&gt;interoperability with systems using 64-bit integers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ECMAScript 2026 also includes &lt;code&gt;JSON.rawJSON()&lt;/code&gt;, which lets code provide validated raw JSON for primitive values during serialization.&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;exactId&lt;/span&gt; &lt;span class="o"&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;rawJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123456789012345678901234567890&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;payload&lt;/span&gt; &lt;span class="o"&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="na"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;exactId&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;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// {"transactionId":123456789012345678901234567890}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This offers more control over output that cannot be represented exactly as a regular JavaScript &lt;code&gt;Number&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use it carefully
&lt;/h3&gt;

&lt;p&gt;Raw JSON is a precision and interoperability tool, not a general string-concatenation shortcut.&lt;/p&gt;

&lt;p&gt;Only use validated values and keep the expected schema explicit.&lt;/p&gt;




&lt;h2&gt;
  
  
  A quick migration checklist
&lt;/h2&gt;

&lt;p&gt;You do not need to refactor an entire codebase to benefit from ES2026.&lt;/p&gt;

&lt;p&gt;Look for these existing patterns:&lt;/p&gt;

&lt;h3&gt;
  
  
  Manual async collection
&lt;/h3&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;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &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;item&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&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;Consider:&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;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Repeated Map initialization
&lt;/h3&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&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="nx"&gt;map&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;createValue&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consider:&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrInsertComputed&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="nx"&gt;createValue&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Array spreads used only to join iterables
&lt;/h3&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;combined&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="nx"&gt;sourceA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sourceB&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consider a lazy sequence:&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;combined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;sourceA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;sourceB&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cross-context error checks
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consider:&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="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom binary conversion helpers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;customBytesToHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consider:&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="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toHex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Large integers parsed from JSON
&lt;/h3&gt;

&lt;p&gt;If an API returns integer values outside the safe &lt;code&gt;Number&lt;/code&gt; range, consider parsing the original source into &lt;code&gt;BigInt&lt;/code&gt; or a decimal representation.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to use these features safely today
&lt;/h2&gt;

&lt;p&gt;A feature being part of the ECMAScript standard does not guarantee that every browser, embedded webview, server runtime, or build target already supports it.&lt;/p&gt;

&lt;p&gt;A simple feature check can help:&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;supportsFromAsync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromAsync&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&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;supportsPreciseSum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sumPrecise&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&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;supportsErrorCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isError&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&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;supportsHex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toHex&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a production project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check your browser and runtime support matrix.&lt;/li&gt;
&lt;li&gt;Test using the same versions as your deployment environment.&lt;/li&gt;
&lt;li&gt;Add a fallback or polyfill where appropriate.&lt;/li&gt;
&lt;li&gt;Avoid assuming that transpilation automatically provides new runtime APIs.&lt;/li&gt;
&lt;li&gt;Upgrade dependencies and CI images deliberately.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Transpilers can transform syntax, but methods such as &lt;code&gt;Math.sumPrecise()&lt;/code&gt; and &lt;code&gt;Array.fromAsync()&lt;/code&gt; require runtime support or an implementation supplied by your application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;ECMAScript 2026 is a good example of language evolution focused on practical improvements rather than dramatic syntax changes.&lt;/p&gt;

&lt;p&gt;Its additions address familiar problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;collecting asynchronous data,&lt;/li&gt;
&lt;li&gt;initializing cached values,&lt;/li&gt;
&lt;li&gt;combining lazy sequences,&lt;/li&gt;
&lt;li&gt;identifying errors reliably,&lt;/li&gt;
&lt;li&gt;reducing summation error,&lt;/li&gt;
&lt;li&gt;converting binary data,&lt;/li&gt;
&lt;li&gt;preserving JSON precision.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these features will replace your framework or redesign your architecture. That is exactly why they are valuable: they make ordinary JavaScript code shorter, clearer, and more expressive.&lt;/p&gt;

&lt;p&gt;My first candidates for immediate adoption are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Map.prototype.getOrInsertComputed()&lt;/code&gt; for caches and grouping,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Array.fromAsync()&lt;/code&gt; for finite asynchronous sources,&lt;/li&gt;
&lt;li&gt;the new &lt;code&gt;Uint8Array&lt;/code&gt; encoding methods for API and crypto work.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Which ECMAScript 2026 feature are you most likely to use first?&lt;/p&gt;




&lt;h2&gt;
  
  
  Sources and further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://262.ecma-international.org/" rel="noopener noreferrer"&gt;ECMAScript 2026 Language Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ecma-international.org/publications-and-standards/standards/ecma-262/" rel="noopener noreferrer"&gt;ECMA-262 — Ecma International&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pawelgrzybek.com/whats-new-in-ecmascript-2026/" rel="noopener noreferrer"&gt;What’s new in ECMAScript 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.infoworld.com/article/4193461/ecmascript-2026-specification-approved.html" rel="noopener noreferrer"&gt;ECMAScript 2026 specification approved&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Connect with Me
&lt;/h3&gt;

&lt;p&gt;If you found this guide helpful, let's connect and discuss modern development workflows!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/johnnylemonny" rel="noopener noreferrer"&gt;johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;✍️ &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/johnnylemonny"&gt;johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This article was created with the help of AI&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>node</category>
    </item>
    <item>
      <title>Passionaut: Turn Any Passion into an AI-Generated 3D Knowledge Atlas</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Sat, 11 Jul 2026 13:15:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/passionaut-turn-any-passion-into-an-ai-generated-3d-knowledge-atlas-25gh</link>
      <guid>https://dev.to/johnnylemonny/passionaut-turn-any-passion-into-an-ai-generated-3d-knowledge-atlas-25gh</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-07-09"&gt;Weekend Challenge: Passion Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;What if learning about a passion felt less like reading a list of search results—and more like exploring a universe?&lt;/p&gt;

&lt;p&gt;That question led me to build &lt;strong&gt;Passionaut&lt;/strong&gt;, an AI-powered, interactive 3D knowledge atlas that transforms almost any passion or domain into an explorable constellation of concepts, sub-disciplines, projects, techniques, and connections.&lt;/p&gt;

&lt;p&gt;Enter a topic such as &lt;strong&gt;Astrophysics&lt;/strong&gt;, &lt;strong&gt;Mechanical Keyboards&lt;/strong&gt;, or &lt;strong&gt;Procedural Generation&lt;/strong&gt;, and Passionaut uses Google Gemini AI to generate a structured deep dive into that subject.&lt;/p&gt;

&lt;p&gt;The generated knowledge is not presented as another wall of text.&lt;/p&gt;

&lt;p&gt;Instead, it becomes a fully navigable 3D constellation.&lt;/p&gt;

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

&lt;p&gt;🌌 &lt;strong&gt;&lt;a href="https://johnnylemonny.github.io/passionaut/" rel="noopener noreferrer"&gt;Launch the live demo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Passionaut&lt;/strong&gt; is an interactive 3D knowledge graph designed to answer one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How deep does my passion go?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A user enters any passion, interest, or domain. Google Gemini then generates a structured map of the subject, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;core concepts,&lt;/li&gt;
&lt;li&gt;sub-disciplines,&lt;/li&gt;
&lt;li&gt;important techniques,&lt;/li&gt;
&lt;li&gt;practical projects,&lt;/li&gt;
&lt;li&gt;useful tools,&lt;/li&gt;
&lt;li&gt;and meaningful relationships between them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Passionaut converts this information into an immersive 3D constellation rendered directly in the browser.&lt;/p&gt;

&lt;p&gt;Every node represents part of the selected domain. Connections between nodes reveal how individual ideas belong to the larger knowledge landscape.&lt;/p&gt;

&lt;p&gt;Users can navigate the constellation, inspect dynamically scaled 3D labels, select individual nodes, and open a deep-dive panel containing more information and an importance score.&lt;/p&gt;

&lt;p&gt;The goal was not to create another linear learning checklist.&lt;/p&gt;

&lt;p&gt;I wanted to make curiosity spatial.&lt;/p&gt;




&lt;h2&gt;
  
  
  Inspiration
&lt;/h2&gt;

&lt;p&gt;People rarely discover a passion in a perfectly organized sequence.&lt;/p&gt;

&lt;p&gt;One concept leads to another. A tool introduces a technique. A historical breakthrough reveals an entire discipline. A simple question opens a path toward ten more questions.&lt;/p&gt;

&lt;p&gt;Passions behave less like lists and more like constellations: individual points become more meaningful when we can see the connections between them.&lt;/p&gt;

&lt;p&gt;Search engines are excellent when we already know what to ask. But when entering an unfamiliar field, the more interesting question is often:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What exists inside this world, and where could I go next?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Passionaut was built to explore that question.&lt;/p&gt;

&lt;p&gt;By combining generative AI with a spatial interface, the application turns an abstract and potentially overwhelming subject into a concrete environment that users can navigate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try it in four steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open the live application.&lt;/li&gt;
&lt;li&gt;Enter your Google Gemini API key when prompted.&lt;/li&gt;
&lt;li&gt;Search for a passion or domain.&lt;/li&gt;
&lt;li&gt;Explore the generated 3D constellation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Good topics to try include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Astrophysics&lt;/li&gt;
&lt;li&gt;Mechanical Keyboards&lt;/li&gt;
&lt;li&gt;Procedural Generation&lt;/li&gt;
&lt;li&gt;Game Development&lt;/li&gt;
&lt;li&gt;Electronic Music&lt;/li&gt;
&lt;li&gt;Robotics&lt;/li&gt;
&lt;li&gt;Photography&lt;/li&gt;
&lt;li&gt;Artificial Intelligence&lt;/li&gt;
&lt;li&gt;Sustainable Architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Select a node to open its detail panel, then move through the graph to discover related ideas.&lt;/p&gt;

&lt;p&gt;The application also remembers your five most recent successful searches, allowing you to return to a previously generated atlas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Share an atlas
&lt;/h3&gt;

&lt;p&gt;Passionaut supports shareable query links.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Copy Share Link&lt;/strong&gt; after generating an atlas. The resulting URL contains the selected topic as a query parameter.&lt;/p&gt;

&lt;p&gt;When another user opens the link, Passionaut automatically generates that specific atlas in real time.&lt;/p&gt;

&lt;p&gt;For example, a shared link can point directly to an atlas for Astrophysics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://johnnylemonny.github.io/passionaut/?q=Astrophysics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  About the API key
&lt;/h3&gt;

&lt;p&gt;Passionaut follows a bring-your-own-key model.&lt;/p&gt;

&lt;p&gt;Your Gemini API key is stored locally in your browser. The application is statically hosted and does not rely on a custom backend for storing API credentials.&lt;/p&gt;

&lt;p&gt;A free Gemini API key can be created in &lt;a href="https://aistudio.google.com/apikey" rel="noopener noreferrer"&gt;https://aistudio.google.com/apikey&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;The complete source code is available on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/johnnylemonny/passionaut" rel="noopener noreferrer"&gt;github.com/johnnylemonny/passionaut&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Passionaut is open source and licensed under the MIT License.&lt;/p&gt;

&lt;p&gt;If you find the project interesting, consider giving it a ⭐ on GitHub.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Passionaut is built around a pipeline that converts an unrestricted natural-language topic into structured data and then turns that data into an interactive environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Accepting an open-ended passion
&lt;/h3&gt;

&lt;p&gt;The experience begins with a simple search input.&lt;/p&gt;

&lt;p&gt;The user does not need to understand the structure of a field before exploring it. Discovering that structure is the purpose of the application.&lt;/p&gt;

&lt;p&gt;The input can be broad, specific, technical, or creative.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Generating structured knowledge with Gemini
&lt;/h3&gt;

&lt;p&gt;Passionaut uses &lt;strong&gt;Gemini 3.1 Flash-Lite&lt;/strong&gt; through the &lt;code&gt;@google/genai&lt;/code&gt; SDK.&lt;/p&gt;

&lt;p&gt;Instead of asking Gemini for a conventional article, the application requests structured JSON describing the selected domain.&lt;/p&gt;

&lt;p&gt;The generated data represents elements such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sub-disciplines,&lt;/li&gt;
&lt;li&gt;concepts,&lt;/li&gt;
&lt;li&gt;techniques,&lt;/li&gt;
&lt;li&gt;projects,&lt;/li&gt;
&lt;li&gt;descriptions,&lt;/li&gt;
&lt;li&gt;importance values,&lt;/li&gt;
&lt;li&gt;and relationships.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This distinction is essential.&lt;/p&gt;

&lt;p&gt;A rendered knowledge graph cannot be built from an unstructured paragraph alone. It needs recognizable entities and connections that can be translated into nodes and links.&lt;/p&gt;

&lt;p&gt;Gemini provides enough flexibility to generate these structures for completely different domains without requiring a manually curated database for every possible passion.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Converting the response into a graph
&lt;/h3&gt;

&lt;p&gt;The structured Gemini response is transformed into graph data.&lt;/p&gt;

&lt;p&gt;Individual concepts become nodes, while relationships between concepts become links.&lt;/p&gt;

&lt;p&gt;Importance values can influence how prominently information appears in the visualization, helping users recognize the hierarchy inside a generated atlas.&lt;/p&gt;

&lt;p&gt;This stage connects the AI layer with the visualization layer: Gemini defines the knowledge landscape, while the graph system determines how users experience it.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Rendering an interactive 3D constellation
&lt;/h3&gt;

&lt;p&gt;The visualization is powered by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Three.js&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React Three Fiber&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;react-force-graph-3d&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React Spring&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these technologies render the generated graph as a fully navigable 3D constellation.&lt;/p&gt;

&lt;p&gt;Users can rotate the scene, change their viewing position, inspect connections, and select nodes.&lt;/p&gt;

&lt;p&gt;Instead of presenting knowledge as a static hierarchy, the 3D layout communicates that every domain is a network of interconnected ideas.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Building dynamic 3D typography
&lt;/h3&gt;

&lt;p&gt;A graph becomes difficult to use if its labels are too small, frequently overlap, or are cut off.&lt;/p&gt;

&lt;p&gt;Passionaut uses dynamically sized 3D labels that float beside their corresponding nodes.&lt;/p&gt;

&lt;p&gt;The label scale helps communicate importance while keeping concepts identifiable throughout the scene.&lt;/p&gt;

&lt;p&gt;This was one of the most important usability considerations because the visualization needed to remain informative rather than becoming purely decorative.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Creating the deep-space interface
&lt;/h3&gt;

&lt;p&gt;The interface was built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js 16&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React 19&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tailwind CSS v4&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lucide Icons&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React Spring&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted the application to feel like a specialized instrument for navigating knowledge rather than a conventional dashboard.&lt;/p&gt;

&lt;p&gt;The dark-space HUD, motion, suggestion chips, search history, and detailed node panel all support that direction.&lt;/p&gt;

&lt;p&gt;The visual effects are designed to reinforce exploration without making the knowledge harder to read.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Synthesizing audio in the browser
&lt;/h3&gt;

&lt;p&gt;Passionaut includes custom interaction sounds created with the native &lt;strong&gt;Web Audio API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The application synthesizes effects such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ticks when hovering,&lt;/li&gt;
&lt;li&gt;a D5 tone when selecting a node,&lt;/li&gt;
&lt;li&gt;and sweeping sounds when starting a search.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These sounds are generated directly in the browser. No external audio asset library is required.&lt;/p&gt;

&lt;p&gt;The audio layer makes the interface feel more responsive while preserving the application’s futuristic identity.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Managing state and recent searches
&lt;/h3&gt;

&lt;p&gt;Application state is managed with &lt;strong&gt;Zustand&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Local storage persistence allows Passionaut to remember the five most recent successful atlases. This gives users a quick way to move between previously explored topics without maintaining a user account.&lt;/p&gt;

&lt;p&gt;The Gemini API key is also kept locally in the user’s browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Generating shareable links
&lt;/h3&gt;

&lt;p&gt;A generated atlas can be shared using a URL query parameter.&lt;/p&gt;

&lt;p&gt;When a recipient opens a Passionaut link containing a query, the application reads the selected topic and generates the associated atlas.&lt;/p&gt;

&lt;p&gt;This makes the subject itself shareable without requiring a backend database to permanently store every graph.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Deploying as a static application
&lt;/h3&gt;

&lt;p&gt;Passionaut uses the Next.js static export workflow and is deployed on GitHub Pages.&lt;/p&gt;

&lt;p&gt;The application does not require a dedicated application server. Users provide their own Gemini API key, and the browser communicates with the Gemini API to generate the requested knowledge structure.&lt;/p&gt;

&lt;p&gt;This architecture keeps deployment simple and makes the project easy to host as a public demonstration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technical Stack
&lt;/h2&gt;

&lt;p&gt;Here is the complete technical stack behind Passionaut:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework:&lt;/strong&gt; Next.js 16 with App Router and static export&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI:&lt;/strong&gt; React 19&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling:&lt;/strong&gt; Tailwind CSS v4&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Icons:&lt;/strong&gt; Lucide Icons&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animations:&lt;/strong&gt; React Spring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3D rendering:&lt;/strong&gt; Three.js and React Three Fiber&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graph visualization:&lt;/strong&gt; react-force-graph-3d&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State management:&lt;/strong&gt; Zustand with local storage persistence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI integration:&lt;/strong&gt; Google Gemini through &lt;code&gt;@google/genai&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI model:&lt;/strong&gt; Gemini 3.1 Flash-Lite&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio:&lt;/strong&gt; Native Web Audio API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment:&lt;/strong&gt; GitHub Pages&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Interesting Challenges
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Making AI output visualization-ready
&lt;/h3&gt;

&lt;p&gt;Natural-language output is flexible, but a graph requires predictable structure.&lt;/p&gt;

&lt;p&gt;The generated information must be converted into entities and relationships that the visualization can reliably interpret.&lt;/p&gt;

&lt;p&gt;This meant treating prompt design and structured output handling as parts of the application architecture—not as an isolated AI feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supporting completely different passions
&lt;/h3&gt;

&lt;p&gt;Astrophysics, mechanical keyboards, music, and game development have very different vocabularies and internal structures.&lt;/p&gt;

&lt;p&gt;Passionaut needs to create a useful constellation for each domain without assuming that every subject can be represented in exactly the same way.&lt;/p&gt;

&lt;p&gt;Gemini provides the flexibility to interpret each passion in context while still producing data for a common graph system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Balancing complexity and readability
&lt;/h3&gt;

&lt;p&gt;A dense 3D graph can look impressive while being practically impossible to use.&lt;/p&gt;

&lt;p&gt;The challenge was to communicate the scale and interconnectedness of a passion without letting the visualization become meaningless visual noise.&lt;/p&gt;

&lt;p&gt;Dynamic labels, node importance, navigation, and the detail panel all help preserve the graph’s utility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Combining information with atmosphere
&lt;/h3&gt;

&lt;p&gt;Passionaut is both a knowledge tool and an interactive audiovisual experience.&lt;/p&gt;

&lt;p&gt;WebGL, animation, and Web Audio can make the application memorable, but they should never distract users from the generated concepts.&lt;/p&gt;

&lt;p&gt;The guiding design principle was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every effect should make discovery feel better without getting in the way of discovery.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Running without a custom backend
&lt;/h3&gt;

&lt;p&gt;Static deployment makes Passionaut easy to host, but it also requires a different approach to API access, state persistence, search history, and sharing.&lt;/p&gt;

&lt;p&gt;The bring-your-own-key model and browser-based storage allow the application to remain fully static while still generating new atlases on demand.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Use of Google AI
&lt;/h2&gt;

&lt;p&gt;I am submitting Passionaut for &lt;strong&gt;Best Use of Google AI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Gemini is not an optional chatbot placed beside the main application. It is the knowledge engine that creates the environment the user explores.&lt;/p&gt;

&lt;p&gt;Gemini 3.1 Flash-Lite transforms an unrestricted topic into structured JSON containing concepts, sub-disciplines, projects, techniques, importance values, and relationships.&lt;/p&gt;

&lt;p&gt;That output directly determines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which nodes appear,&lt;/li&gt;
&lt;li&gt;how the nodes are connected,&lt;/li&gt;
&lt;li&gt;which concepts receive greater visual importance,&lt;/li&gt;
&lt;li&gt;what appears in the deep-dive detail panel,&lt;/li&gt;
&lt;li&gt;and which paths of discovery are available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without Gemini, Passionaut would require a manually curated database for every supported domain.&lt;/p&gt;

&lt;p&gt;With Gemini, the same visualization system can generate an atlas for subjects as different as astrophysics, mechanical keyboards, procedural generation, music, photography, and game development.&lt;/p&gt;

&lt;p&gt;Gemini does not merely describe the universe.&lt;/p&gt;

&lt;p&gt;Gemini helps create the universe that the user explores.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Building Passionaut reinforced an important idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI becomes especially powerful when its output changes the interface itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A generated paragraph can be helpful, but generated structure can become a visualization, a simulation, a map, or an entire explorable environment.&lt;/p&gt;

&lt;p&gt;In Passionaut, AI output is not the final presentation layer. It becomes material for the application.&lt;/p&gt;

&lt;p&gt;I also learned that knowledge visualization is not only a rendering problem.&lt;/p&gt;

&lt;p&gt;It requires decisions about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;information hierarchy,&lt;/li&gt;
&lt;li&gt;relationships,&lt;/li&gt;
&lt;li&gt;visual density,&lt;/li&gt;
&lt;li&gt;label readability,&lt;/li&gt;
&lt;li&gt;interaction feedback,&lt;/li&gt;
&lt;li&gt;spatial navigation,&lt;/li&gt;
&lt;li&gt;and where the user’s attention should go first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The strongest results came from treating AI, 3D rendering, animation, sound, and interface design as parts of one connected system.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;There are several directions I would like to explore next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;saving generated constellations permanently,&lt;/li&gt;
&lt;li&gt;exporting knowledge maps,&lt;/li&gt;
&lt;li&gt;comparing two related passions,&lt;/li&gt;
&lt;li&gt;adding alternative non-3D navigation modes,&lt;/li&gt;
&lt;li&gt;generating guided learning journeys,&lt;/li&gt;
&lt;li&gt;improving keyboard navigation and accessibility,&lt;/li&gt;
&lt;li&gt;expanding nodes into deeper sub-constellations,&lt;/li&gt;
&lt;li&gt;adding collaborative exploration,&lt;/li&gt;
&lt;li&gt;and allowing users to customize the depth and complexity of an atlas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The direction I find most exciting is recursive exploration.&lt;/p&gt;

&lt;p&gt;A user could select one concept inside a constellation and generate a completely new atlas around it. That would turn Passionaut into an almost endless journey through connected knowledge.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Passionaut began with a simple idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A passion is not a list. It is a universe of connected ideas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Google Gemini provides the knowledge structure.&lt;/p&gt;

&lt;p&gt;Three.js gives that structure a spatial form.&lt;/p&gt;

&lt;p&gt;Web Audio adds a responsive layer of feedback.&lt;/p&gt;

&lt;p&gt;Together, these technologies turn curiosity into something users can explore.&lt;/p&gt;




&lt;p&gt;🌌 &lt;strong&gt;&lt;a href="https://johnnylemonny.github.io/passionaut/" rel="noopener noreferrer"&gt;Try Passionaut&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;&lt;a href="https://github.com/johnnylemonny/passionaut" rel="noopener noreferrer"&gt;Explore the source code&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>threejs</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Next.js Finally Fixed Caching (And My Database Is Sighing in Relief)</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Thu, 09 Jul 2026 13:02:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/nextjs-finally-fixed-caching-and-my-database-is-sighing-in-relief-117l</link>
      <guid>https://dev.to/johnnylemonny/nextjs-finally-fixed-caching-and-my-database-is-sighing-in-relief-117l</guid>
      <description>&lt;p&gt;I spent a miserable afternoon a while back debugging a production issue where a user's private financial dashboard was showing cached data from a completely different account. Why? Because Next.js 14 decided that a standard, innocent-looking &lt;code&gt;fetch()&lt;/code&gt; call should be cached aggressively until the end of time unless you explicitly went out of your way to block it.&lt;/p&gt;

&lt;p&gt;It was the ultimate frontend footgun. &lt;/p&gt;

&lt;p&gt;Thankfully, the ecosystem listened. With the recent maturity and widespread production adoption of Next.js 15 and the latest 16.x patches, the Vercel team completely flipped the script. Caching is now &lt;strong&gt;opt-in by default&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;If you haven't audited your full-stack data fetching patterns lately, the era of pulling your hair out over stale data is over—but it means you need to adjust how you write your data layer today.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Nightmare of "Everything is Cached"
&lt;/h2&gt;

&lt;p&gt;In previous versions, Next.js tried to be clever. It assumed that if you were making a GET request, you wanted it to be as fast as possible, so it statically cached the result at build time or on the first request. &lt;/p&gt;

&lt;p&gt;While that worked great for basic blogs, it was a disaster for real-world dynamic apps. You had to constantly litter your code with things like:&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;// The old boilerplate dance just to keep data fresh&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;revalidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="c1"&gt;// or&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;[https://api.example.com/data](https://api.example.com/data)&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;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If you forgot that single configuration object on an API route handler, your dynamic endpoint was suddenly serving stale data to your users, and your serverless functions were returning zombie responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Modern Fix: Uncached by Default
&lt;/h2&gt;

&lt;p&gt;In the current Next.js architecture, &lt;code&gt;fetch&lt;/code&gt; requests and GET Route Handlers are &lt;strong&gt;uncached by default&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you don't explicitly ask for caching, Next.js treats your request as dynamic. Your database gets queried when the user requests the page, just like traditional backend frameworks (like Node/Express, Rails, or Laravel) have done for decades.&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;// How we write data fetching now (Next.js 15/16 baseline)&lt;/span&gt;
&lt;span class="c1"&gt;// This hits the API live on every single request automatically.&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;[https://api.yourbackend.com/users/me](https://api.yourbackend.com/users/me)&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;user&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you actually &lt;em&gt;want&lt;/em&gt; to cache a heavy public payload (like a product list or a public configuration), you now have to be intentional about it:&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;// Explicitly opting into performance optimization&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;staticData&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;[https://api.yourbackend.com/products](https://api.yourbackend.com/products)&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;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;force-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This simple swap dramatically lowers the cognitive load of shipping full-stack apps. You optimize for correctness first, then opt into performance later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Watch Out for the Asynchronous Request APIs
&lt;/h2&gt;

&lt;p&gt;The caching overhaul also brought another massive structural change that catches developers off guard when upgrading: request-scoped metadata APIs are now completely asynchronous.&lt;/p&gt;

&lt;p&gt;If you are reading cookies, headers, or route params inside a Server Component, you can no longer access them synchronously.&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;// ❌ This will throw an error in modern Next.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cookieStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cookies&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cookieStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//   The right way&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cookieStore&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;cookies&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cookieStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Why did they do this? To make &lt;strong&gt;Partial Prerendering (PPR)&lt;/strong&gt; actually work. By making these APIs return a promise, the framework can instantly serve a static HTML shell of your page while waiting for the request-dependent dynamic parts (like user sessions or headers) to resolve and stream into the client.&lt;/p&gt;




&lt;h3&gt;
  
  
  Over to you
&lt;/h3&gt;

&lt;p&gt;Did you get bitten by the old aggressive caching model, or did you actually prefer things being fast by default? Let's talk in the comments.&lt;/p&gt;




&lt;h3&gt;
  
  
  Connect with Me
&lt;/h3&gt;

&lt;p&gt;If you found this guide helpful, let's connect and discuss modern development workflows!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/johnnylemonny" rel="noopener noreferrer"&gt;johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;✍️ &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/johnnylemonny"&gt;johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This article was created with the help of AI&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Stop Over-Optimizing Performance: The Modern Full-Stack Toolkit in 2026</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Wed, 01 Jul 2026 12:35:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/stop-over-optimizing-performance-the-modern-full-stack-toolkit-in-2026-2i97</link>
      <guid>https://dev.to/johnnylemonny/stop-over-optimizing-performance-the-modern-full-stack-toolkit-in-2026-2i97</guid>
      <description>&lt;p&gt;Let’s face it: if your current frontend optimization strategy still involves manually auditing codebases for missing &lt;code&gt;useMemo&lt;/code&gt; hooks, micro-managing dependency arrays, or aggressively fighting layout shifts with complex client-side state management, you are wasting your engineering leverage.&lt;/p&gt;

&lt;p&gt;As we cross the midpoint of 2026, web framework architecture has quietly undergone a massive shift. We have firmly moved out of the era of manual performance tweaking and entered the era of &lt;strong&gt;automated, compile-time optimization&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal of modern development is no longer just shipping fewer kilobytes to human users—it's also about optimizing data chunk delivery for AI web crawlers that evaluate your site in real-time. &lt;/p&gt;

&lt;p&gt;Here is how the modern full-stack ecosystem redefined performance this year, and what you should focus on instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Death of Manual Memoization (Thanks, React Compiler)
&lt;/h2&gt;

&lt;p&gt;For years, React developers bore the cognitive load of rendering performance. One misplaced reference and your entire component tree re-rendered down to the root.&lt;/p&gt;

&lt;p&gt;With the absolute maturity and default adoption of the &lt;strong&gt;React Compiler&lt;/strong&gt; across production frameworks, that paradigm is officially legacy code. The compiler handles component memoization automatically at the build step by analyzing javascript structures 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;// ❌ THE OLD WAY (Pre-2026 Manual Overhead)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ExpensiveComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="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;processedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&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;computeHeavyMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&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;handleAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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="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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DataGrid&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{processedData}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onAction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{handleAction}&lt;/span&gt;&lt;span class="dl"&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="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;//   THE MODERN WAY (Zero Performance Boilerplate)&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;ModernComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computeHeavyMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleAction&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="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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DataGrid&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{processedData}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onAction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{handleAction}&lt;/span&gt;&lt;span class="dl"&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="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Because the compiler injects optimization markers directly into the output code, human engineers can stop arguing about code architecture aesthetics and write clean, plain, idiomatically correct JavaScript.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Streaming SSR is the New Baseline for AEO
&lt;/h2&gt;

&lt;p&gt;Server-Side Rendering (SSR) used to be an all-or-nothing game. The server fetched all data, rendered the full HTML string, sent it to the browser, and then hydrated the entire view.&lt;/p&gt;

&lt;p&gt;Today, production setups rely heavily on &lt;strong&gt;Streaming SSR&lt;/strong&gt; mixed with hybrid data fetching architectures (like Next.js Server Components and SvelteKit Runes). Instead of blocking the page load for slow API responses, pages are delivered in independent streaming chunks.&lt;/p&gt;

&lt;p&gt;This has become vital not just for your Core Web Vitals, but for &lt;strong&gt;AEO (Answer Engine Optimization)&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔍 &lt;strong&gt;Why this matters right now:&lt;/strong&gt; Modern search indexes and AI aggregators scrape live data using real-time LLM agents. If your main page content is trapped behind a client-side loading spinner, an AI crawler won't wait for the hydration cycle. It reads the initial streamed server chunk and leaves. High performance means instant discoverability.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Radical Architectural Minimalism
&lt;/h2&gt;

&lt;p&gt;Look at the trending boilerplate setups making waves in production this season. The visual noise is disappearing, and that translates directly to better performance strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fewer DOM Nodes:&lt;/strong&gt; Complex layout hacks are being replaced by native CSS features (like Container Queries and dynamic anchor positioning), cutting out deep wrappers that bloat the virtual DOM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build-Time Shift:&lt;/strong&gt; Frameworks like SvelteKit and Astro have proved that running heavy logic during compilation rather than execution yields smaller bundle sizes, ensuring great UX even on low-powered mobile devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serverless Edge Runtimes:&lt;/strong&gt; Computing is moving away from centralized data centers closer to the end user via Edge functions, keeping time-to-first-byte (TTFB) low globally.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Where You Should Actually Spend Your Time
&lt;/h2&gt;

&lt;p&gt;If the toolchains and compilers handle runtime rendering optimizations, where do you look for engineering impact?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Strict Type Contracts:&lt;/strong&gt; Spend time establishing rock-solid TypeScript definitions between your client and backend APIs. Predictable data types prevent downstream hydration mismatches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robust Test Coverage:&lt;/strong&gt; Write end-to-end tests that validate data persistence and edge-case rendering boundaries. If the compiler optimizes your code, your tests must ensure the business logic remains intact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Hydration Architecture:&lt;/strong&gt; Focus on optimizing &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;where&lt;/em&gt; data is fetched. Organize your databases, design efficient indexes, and ensure your APIs return predictable payloads.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Let's connect and discuss!
&lt;/h3&gt;

&lt;p&gt;What performance optimizations have you safely delegated to your compiler this year? Are you embracing the shift to server-driven architecture or keeping your logic client-side? Let me know in the comments!&lt;/p&gt;




&lt;h3&gt;
  
  
  Connect with Me
&lt;/h3&gt;

&lt;p&gt;If you found this guide helpful, let's connect and discuss modern development workflows!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/johnnylemonny" rel="noopener noreferrer"&gt;johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;✍️ &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/johnnylemonny"&gt;johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This article was created with the help of AI&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Stop Paying for GitHub Copilot: Build a Free, 100% Private AI Assistant Locally</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Tue, 23 Jun 2026 12:15:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/stop-paying-for-github-copilot-build-a-free-100-private-ai-assistant-locally-5dpd</link>
      <guid>https://dev.to/johnnylemonny/stop-paying-for-github-copilot-build-a-free-100-private-ai-assistant-locally-5dpd</guid>
      <description>&lt;p&gt;The landscape of AI coding assistants has completely shifted. While cloud-based subscriptions like GitHub Copilot or Claude Pro are excellent, they come with two major pain points: &lt;strong&gt;recurring monthly costs&lt;/strong&gt; and &lt;strong&gt;privacy concerns&lt;/strong&gt; regarding your proprietary code.&lt;/p&gt;

&lt;p&gt;Thanks to the incredible advancements in efficiency, you can now run state-of-the-art coding LLMs &lt;em&gt;directly on your local machine&lt;/em&gt; with zero latency, absolute privacy, and absolutely no cost. &lt;/p&gt;

&lt;p&gt;In this guide, we will set up a blazing-fast, context-aware local AI coding assistant using &lt;strong&gt;Ollama&lt;/strong&gt; and &lt;strong&gt;Continue.dev&lt;/strong&gt; in VS Code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Go Local?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;💰 &lt;strong&gt;Cost-Efficient:&lt;/strong&gt; $0/month forever.&lt;/li&gt;
&lt;li&gt;🔒 &lt;strong&gt;100% Private:&lt;/strong&gt; Your code never leaves your local machine. Perfect for NDA-protected or enterprise projects.&lt;/li&gt;
&lt;li&gt;✈️ &lt;strong&gt;Offline Capability:&lt;/strong&gt; Code with full AI assistance on a plane, a train, or anywhere without internet.&lt;/li&gt;
&lt;li&gt;🚀 &lt;strong&gt;Customization:&lt;/strong&gt; Swap models instantly depending on whether you need quick autocomplete or deep architectural reasoning.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;To get a smooth experience, you ideally need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A modern machine (Apple Silicon M-series chips or a Windows/Linux PC with a dedicated Nvidia RTX GPU).&lt;/li&gt;
&lt;li&gt;16GB of RAM/VRAM minimum (8GB can work with highly compressed models, but 16GB+ is the sweet spot).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1: Install Ollama and the Coding Model
&lt;/h2&gt;

&lt;p&gt;Ollama is the easiest way to manage and run LLMs locally.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download and install &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; for your OS.&lt;/li&gt;
&lt;li&gt;Open your terminal and run the following command to download &lt;strong&gt;Qwen2.5-Coder (7B)&lt;/strong&gt; or &lt;strong&gt;DeepSeek-Coder&lt;/strong&gt;. For most modern setups, the 7B (7-billion parameter) model offers the ultimate balance between speed and ChatGPT-4 level coding intelligence.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run qwen2.5-coder:7b

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: If your machine has lower specs, try &lt;code&gt;ollama run qwen2.5-coder:1.5b&lt;/code&gt; for lightning-fast autocompletion.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once the download is complete, you can test it in the terminal, then minimize it. Ollama will run quietly in the background as a local API.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Set Up Continue.dev in Your IDE
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.continue.dev/" rel="noopener noreferrer"&gt;Continue&lt;/a&gt; is an open-source AI code assistant extension that seamlessly replaces the Copilot UI in VS Code or JetBrains IDEs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;VS Code&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to the Extensions marketplace (&lt;code&gt;Ctrl+Shift+X&lt;/code&gt; or &lt;code&gt;Cmd+Shift+X&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;Continue&lt;/strong&gt; and click &lt;strong&gt;Install&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 3: Configure Continue to Use Your Local Model
&lt;/h2&gt;

&lt;p&gt;Once installed, a new icon will appear in your sidebar. Click it, then click the gear icon (⚙️) at the bottom right of the Continue panel to open your &lt;code&gt;config.json&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Replace the contents of the file with the following configuration to link it to your local Ollama instance:&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;"models"&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;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Qwen2.5-Coder 7B"&lt;/span&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;"qwen2.5-coder:7b"&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="nl"&gt;"tabAutocompleteModel"&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;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Qwen2.5-Coder 1.5b"&lt;/span&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;"qwen2.5-coder:1.5b"&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;"customCommands"&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;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;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{{ input }}}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;Write a comprehensive unit test suite for the code above using Jest/Vitest."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Write unit tests"&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="nl"&gt;"contextProviders"&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;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;"codebase"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"params"&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;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;"openFiles"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"params"&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;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;h3&gt;
  
  
  What this configuration does:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chat Model:&lt;/strong&gt; Uses the robust &lt;code&gt;7b&lt;/code&gt; model for complex tasks, refactoring, and general chat conversations in the sidebar (&lt;code&gt;Cmd+L&lt;/code&gt; or &lt;code&gt;Ctrl+L&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tab Autocomplete:&lt;/strong&gt; Uses the ultra-lightweight &lt;code&gt;1.5b&lt;/code&gt; model to instantly suggest inline code as you type, ensuring zero lag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Awareness:&lt;/strong&gt; Allows you to type &lt;code&gt;@codebase&lt;/code&gt; in the chat to let the local AI read your entire project repository securely.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to Maximize Your Local AI Workflow
&lt;/h2&gt;

&lt;p&gt;Now that you are fully set up, here are three essential shortcuts to replace your paid workflow:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Inline Edit (&lt;code&gt;Cmd+I&lt;/code&gt; / &lt;code&gt;Ctrl+I&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Highlight a block of code, press &lt;code&gt;Cmd+I&lt;/code&gt;, and ask the local model to modify it directly. For example: &lt;em&gt;"Refactor this fetch request to use async/await and add error handling."&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Full Project Context (&lt;code&gt;@codebase&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;If you are debugging a tricky bug that spans multiple files, open the chat and type:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;@codebase why is my authentication state resetting on page refresh?&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The extension will index your local files locally, feed relevant snippets to Ollama, and give you an exact answer without a single byte uploaded to the cloud.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Automatic Doc Generation
&lt;/h3&gt;

&lt;p&gt;Highlight a function, hit your chat shortcut, and ask: &lt;em&gt;"Add JSDoc comments to this function explaining the parameters."&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;The era of paying $10-$20 a month per developer for basic AI autocompletion is coming to an end. By leveraging open-weights models and local orchestration tools, you gain total control over your development environment, secure your data, and save money.&lt;/p&gt;

&lt;p&gt;Give it a spin and see how it handles your toughest codebases!&lt;/p&gt;




&lt;h3&gt;
  
  
  Connect with Me
&lt;/h3&gt;

&lt;p&gt;If you found this guide helpful, let's connect and discuss modern development workflows!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/johnnylemonny" rel="noopener noreferrer"&gt;johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;✍️ &lt;strong&gt;DEV.to:&lt;/strong&gt; &lt;a href="https://dev.to/johnnylemonny"&gt;johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>tooling</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Beyond Code Autocomplete: How to Build a Modern Agentic Workflow in 2026</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Tue, 16 Jun 2026 13:07:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/beyond-code-autocomplete-how-to-build-a-modern-agentic-workflow-in-2026-566f</link>
      <guid>https://dev.to/johnnylemonny/beyond-code-autocomplete-how-to-build-a-modern-agentic-workflow-in-2026-566f</guid>
      <description>&lt;p&gt;Let’s be honest: the era of copy-pasting code snippets from a chat UI or blindly accepting basic ghost-text autocomplete is officially over. &lt;/p&gt;

&lt;p&gt;As we move through 2026, the developer landscape has fundamentally shifted. We’ve leapfrogged from AI &lt;em&gt;augmentation&lt;/em&gt; to AI &lt;em&gt;delegation&lt;/em&gt;. With over 70% of engineers using advanced AI tools daily, the competitive advantage isn't knowing how to prompt AI to write a quick utility function. It's knowing how to orchestrate &lt;strong&gt;Autonomous AI Agents&lt;/strong&gt; to manage entire feature lifecycles.&lt;/p&gt;

&lt;p&gt;If you want to stay ahead of the curve, save your cognitive load, and prevent your codebase from turning into an AI-generated spaghetti monster, you need to upgrade your setup. &lt;/p&gt;

&lt;p&gt;Here is what a modern, high-leverage developer workflow looks like today.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Shift to Bounded Agentic Workflows
&lt;/h2&gt;

&lt;p&gt;We’ve moved past simple extensions. Modern tools like &lt;strong&gt;Claude Code&lt;/strong&gt;, &lt;strong&gt;Cursor’s Agent Mode&lt;/strong&gt;, and next-gen &lt;strong&gt;Copilot&lt;/strong&gt; don’t just sit in your sidebar waiting for a prompt. They have &lt;strong&gt;repository intelligence&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;They can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read your entire file structure and understand architectural intent.&lt;/li&gt;
&lt;li&gt;Independently formulate multi-step execution plans.&lt;/li&gt;
&lt;li&gt;Write code across multiple files, run tests in your terminal, read the error output, and self-correct before you even look at the PR.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;The 2026 Mindset:&lt;/strong&gt; You are no longer a "line mechanic" writing every block of boilerplate by hand. You are a &lt;strong&gt;System Architect&lt;/strong&gt; and a &lt;strong&gt;Code Reviewer&lt;/strong&gt;. Your job is to define constraints, review intent, and validate outputs.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Enter MCP: The "USB-C Port" for AI Context
&lt;/h2&gt;

&lt;p&gt;One of the quietest yet biggest revolutions happening right now is the widespread adoption of the &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Originally introduced as an open standard to connect AI models to secure data sources, MCP has become the integration layer of choice. Instead of you copying and pasting logs, database schemas, or API docs into an LLM, your development environment uses MCP servers to securely stream that context directly to the agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
┌──────────────┐          MCP          ┌─────────────────────────┐
│              │◄─────────────────────►│ Your local filesystem   │
│   AI Agent   │          MCP          ├─────────────────────────┤
│ (Cursor/IDE) │◄─────────────────────►│ Production logs (Sentry)│
│              │          MCP          ├─────────────────────────┤
│              │◄─────────────────────►│ DB Schemas / App APIs   │
└──────────────┘                       └─────────────────────────┘

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

&lt;/div&gt;



&lt;p&gt;When your AI agent can safely inspect a distributed trace in Sentry, cross-reference it with your database schema, and apply a patch directly to your repository, debugging friction drops to near zero.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Why "Boring" Codebase Qualities are Your Superpower
&lt;/h2&gt;

&lt;p&gt;There’s a common misconception that because AI can write code, humans can stop worrying about code quality. &lt;strong&gt;The exact opposite is true.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;AI agents are highly sensitive to context. If your codebase is a chaotic mess of unstructured files and implicit types, the AI’s hallucination rate skyrockets. In 2026, building "agent-friendly" codebases is a core engineering skill.&lt;/p&gt;

&lt;p&gt;To get the most out of modern AI workflows, prioritize these "boring" but strategic qualities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strict Type Safety:&lt;/strong&gt; TypeScript has become the absolute baseline. Strong types and explicit data contracts act as guardrails for AI agents, preventing them from generating breaking changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predictable Architecture:&lt;/strong&gt; Stick to clean, conventional folder structures (like those enforced by modern meta-frameworks like Next.js or Nuxt).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive Test Suites:&lt;/strong&gt; If an agent can't run a test suite to verify its work, you cannot trust its autonomy. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explicit Documentation:&lt;/strong&gt; Write clear &lt;code&gt;README.md&lt;/code&gt; files and code comments explaining &lt;em&gt;why&lt;/em&gt; something was built a certain way, not just &lt;em&gt;how&lt;/em&gt;. AI reads your docs to understand your business logic constraints.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Let the Tooling Handle the Micro-Optimizations
&lt;/h2&gt;

&lt;p&gt;Another reason to shift your focus to high-level architecture is that modern frameworks have become incredibly smart. &lt;/p&gt;

&lt;p&gt;With the maturity of tools like the &lt;strong&gt;React Compiler&lt;/strong&gt;, manual performance optimization patterns (like aggressively littering your code with &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt;) are largely things of the past. The compiler handles the optimization at build time, freeing you up to think about data flow, edge computing deployment strategies, and user experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Your 30-Day Action Plan to Upgrade Your Workflow
&lt;/h2&gt;

&lt;p&gt;If you want to compound your engineering leverage this month, stop doing things manually and try this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Adopt an Agent-First Tool:&lt;/strong&gt; If you're still on a legacy editor, spend a week working inside Cursor's Agent Mode or experiment with Claude Code via your CLI. Force yourself to delegate full tasks (e.g., &lt;em&gt;"Refactor this component to use Tailwind v4 and add unit tests"&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explore MCP:&lt;/strong&gt; Set up an MCP server to connect your development environment to your tool stack (like your issue tracker or database client). See how much faster bugs get resolved when the AI has direct context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit for Autonomy:&lt;/strong&gt; Look at your current repository. If an automated agent tried to implement a feature right now, where would it fail? Fix your missing types, update your outdated setup scripts, and make your codebase machine-readable.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What are your thoughts?
&lt;/h3&gt;

&lt;p&gt;Are you embracing "Vibe Coding" and agentic workflows, or are you keeping a tight manual grip on your codebase? Let's discuss in the comments below!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>productivity</category>
      <category>architecture</category>
    </item>
    <item>
      <title>AI Can Build Your UI — But Can It Maintain It?</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Thu, 04 Jun 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/ai-can-build-your-ui-but-can-it-maintain-it-d2l</link>
      <guid>https://dev.to/johnnylemonny/ai-can-build-your-ui-but-can-it-maintain-it-d2l</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Modern Web Development in 2026&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A practical series about building faster, cleaner, more maintainable web applications without chasing every shiny thing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI can build a surprisingly convincing UI in a few minutes.&lt;/p&gt;

&lt;p&gt;That is useful. It is also dangerous in the same way a good mockup is dangerous: it can look finished before the engineering decisions are finished.&lt;/p&gt;

&lt;p&gt;The question is no longer whether AI can generate components.&lt;/p&gt;

&lt;p&gt;The better question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can your team maintain what AI generated six months from now?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Generated UI has a smell
&lt;/h2&gt;

&lt;p&gt;AI-generated frontend often looks impressive at first glance and strange on review.&lt;/p&gt;

&lt;p&gt;Common signs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;duplicated components,&lt;/li&gt;
&lt;li&gt;inconsistent spacing,&lt;/li&gt;
&lt;li&gt;random animation choices,&lt;/li&gt;
&lt;li&gt;inaccessible markup,&lt;/li&gt;
&lt;li&gt;weak loading and error states,&lt;/li&gt;
&lt;li&gt;hard-coded colors,&lt;/li&gt;
&lt;li&gt;unclear state ownership,&lt;/li&gt;
&lt;li&gt;no component contract,&lt;/li&gt;
&lt;li&gt;tests that only prove rendering happened.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this means the tool is bad. It means the output needs engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give AI constraints, not vibes
&lt;/h2&gt;

&lt;p&gt;Bad prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build a beautiful dashboard.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build a dashboard page using our existing Card, Button, Badge, and Table components.
Use semantic HTML. Include loading, empty, and error states.
Do not introduce new colors outside the design tokens.
Keep state local unless it is shared by more than one component.
Add keyboard-accessible interactions.
Return the component and a short review checklist.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AI is much more useful when you give it boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask for states, not just screens
&lt;/h2&gt;

&lt;p&gt;A screen is not a component.&lt;/p&gt;

&lt;p&gt;A component has states:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loading
empty
success
error
permission denied
partial data
saving
saved
validation failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the generated UI only includes the happy path, it is not ready for production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Require component contracts
&lt;/h2&gt;

&lt;p&gt;Before accepting generated UI, define the contract:&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;type&lt;/span&gt; &lt;span class="nx"&gt;InvoiceTableProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;invoices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InvoiceSummary&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&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;empty&lt;/span&gt;&lt;span class="dl"&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;ready&lt;/span&gt;&lt;span class="dl"&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;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onRetry&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onOpenInvoice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;invoiceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InvoiceId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This forces the component to have a clear boundary.&lt;/p&gt;

&lt;p&gt;Without a contract, generated UI tends to reach outward: global state, random fetches, hidden assumptions, and props that grow without discipline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep design tokens non-negotiable
&lt;/h2&gt;

&lt;p&gt;AI loves inventing colors.&lt;/p&gt;

&lt;p&gt;Do not let it.&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;--color-bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0b1020&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--color-surface&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#121a2f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f8fafc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--color-muted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#94a3b8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--color-accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#22c55e&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;Tell the tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use only existing design tokens. Do not invent new hex colors, spacing values, shadows, or font sizes unless explicitly requested.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consistency is not decoration. It is maintainability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make accessibility part of the prompt
&lt;/h2&gt;

&lt;p&gt;Do not ask for accessibility after the component is generated.&lt;/p&gt;

&lt;p&gt;Include it at the start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use semantic HTML.
All interactive elements must be keyboard accessible.
Use visible focus states.
Do not use divs as buttons.
Connect form labels and error messages properly.
Avoid ARIA unless native HTML is not enough.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will not guarantee perfect accessibility, but it raises the floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review generated UI like a pull request
&lt;/h2&gt;

&lt;p&gt;Use this checklist:&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;## AI-generated UI review&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Does it use existing components and tokens?
&lt;span class="p"&gt;-&lt;/span&gt; Are loading, empty, error, and permission states handled?
&lt;span class="p"&gt;-&lt;/span&gt; Is the markup semantic?
&lt;span class="p"&gt;-&lt;/span&gt; Is keyboard interaction supported?
&lt;span class="p"&gt;-&lt;/span&gt; Are props explicit and typed?
&lt;span class="p"&gt;-&lt;/span&gt; Is state owned by the right component?
&lt;span class="p"&gt;-&lt;/span&gt; Are side effects isolated?
&lt;span class="p"&gt;-&lt;/span&gt; Are tests meaningful?
&lt;span class="p"&gt;-&lt;/span&gt; Is there duplicated logic?
&lt;span class="p"&gt;-&lt;/span&gt; Could another developer safely change this later?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last question is the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Good uses of AI in frontend
&lt;/h2&gt;

&lt;p&gt;AI is genuinely helpful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;first drafts,&lt;/li&gt;
&lt;li&gt;test scaffolding,&lt;/li&gt;
&lt;li&gt;refactoring repetitive markup,&lt;/li&gt;
&lt;li&gt;converting rough UI ideas into components,&lt;/li&gt;
&lt;li&gt;writing stories for component states,&lt;/li&gt;
&lt;li&gt;finding accessibility issues,&lt;/li&gt;
&lt;li&gt;generating edge-case checklists,&lt;/li&gt;
&lt;li&gt;explaining unfamiliar code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is less reliable for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;architecture boundaries,&lt;/li&gt;
&lt;li&gt;product intent,&lt;/li&gt;
&lt;li&gt;design consistency,&lt;/li&gt;
&lt;li&gt;long-term ownership,&lt;/li&gt;
&lt;li&gt;subtle accessibility behavior,&lt;/li&gt;
&lt;li&gt;performance tradeoffs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use it where speed helps. Slow down where judgment matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;AI can generate UI. That is no longer the impressive part.&lt;/p&gt;

&lt;p&gt;The impressive part is building a frontend system where generated code has to pass through the same standards as human-written code.&lt;/p&gt;

&lt;p&gt;A fast draft is useful. A maintainable product is better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Syncfusion, “Frontend Development Trends 2026,” published April 28, 2026: &lt;a href="https://www.syncfusion.com/blogs/post/frontend-development-trends" rel="noopener noreferrer"&gt;https://www.syncfusion.com/blogs/post/frontend-development-trends&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2025 JavaScript Rising Stars, published 2026: &lt;a href="https://risingstars.js.org/2025/en" rel="noopener noreferrer"&gt;https://risingstars.js.org/2025/en&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Stack Overflow Blog, “Domain expertise still wanted: the latest trends in AI-assisted knowledge for developers,” published March 16, 2026: &lt;a href="https://stackoverflow.blog/2026/03/16/domain-expertise-still-wanted-the-latest-trends-in-ai/" rel="noopener noreferrer"&gt;https://stackoverflow.blog/2026/03/16/domain-expertise-still-wanted-the-latest-trends-in-ai/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks for reading.&lt;/p&gt;

&lt;p&gt;You can find me here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/johnnylemonny" rel="noopener noreferrer"&gt;https://github.com/johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/johnnylemonny"&gt;https://dev.to/johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Accessibility Is Not a Lighthouse Checkbox</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Tue, 02 Jun 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/accessibility-is-not-a-lighthouse-checkbox-2a1n</link>
      <guid>https://dev.to/johnnylemonny/accessibility-is-not-a-lighthouse-checkbox-2a1n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Modern Web Development in 2026&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A practical series about building faster, cleaner, more maintainable web applications without chasing every shiny thing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Automated accessibility checks are useful.&lt;/p&gt;

&lt;p&gt;They catch missing labels, obvious contrast failures, invalid ARIA, and a lot of mistakes that should never reach production.&lt;/p&gt;

&lt;p&gt;But accessibility is not finished when a tool gives you a green score.&lt;/p&gt;

&lt;p&gt;A green score can still hide a page that is confusing, exhausting, or impossible to use with a keyboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with semantic HTML
&lt;/h2&gt;

&lt;p&gt;The most underrated accessibility tool is still HTML.&lt;/p&gt;

&lt;p&gt;Use the element that matches the job:&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;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Save changes&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/settings"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Account settings&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Main navigation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&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;Do not turn everything into a &lt;code&gt;div&lt;/code&gt; and then rebuild the platform with ARIA.&lt;/p&gt;

&lt;p&gt;ARIA is powerful. It is also easy to misuse. Native semantics are usually safer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keyboard test every important flow
&lt;/h2&gt;

&lt;p&gt;Put the mouse away.&lt;/p&gt;

&lt;p&gt;Can you complete the flow with only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tab
Shift + Tab
Enter
Space
Arrow keys
Escape
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;opening menus,&lt;/li&gt;
&lt;li&gt;closing dialogs,&lt;/li&gt;
&lt;li&gt;submitting forms,&lt;/li&gt;
&lt;li&gt;moving through filters,&lt;/li&gt;
&lt;li&gt;skipping repeated navigation,&lt;/li&gt;
&lt;li&gt;reaching error messages,&lt;/li&gt;
&lt;li&gt;recovering from mistakes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your product cannot be used from a keyboard, it is broken for more people than you think.&lt;/p&gt;

&lt;h2&gt;
  
  
  Focus is part of the interface
&lt;/h2&gt;

&lt;p&gt;Removing focus styles is not polish. It is damage.&lt;/p&gt;

&lt;p&gt;Good focus indicators are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;visible,&lt;/li&gt;
&lt;li&gt;consistent,&lt;/li&gt;
&lt;li&gt;high contrast,&lt;/li&gt;
&lt;li&gt;not hidden behind shadows,&lt;/li&gt;
&lt;li&gt;not dependent on color alone.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:focus-visible&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--focus-ring&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;outline-offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3px&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 goal is not to make focus pretty enough for a screenshot. The goal is to make the current location obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forms need more care than we give them
&lt;/h2&gt;

&lt;p&gt;A good form explains itself before, during, and after input.&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;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email address&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;aria-describedby=&lt;/span&gt;&lt;span class="s"&gt;"email-hint"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email-hint"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Use the address where you want to receive account updates.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;place the message near the field,&lt;/li&gt;
&lt;li&gt;describe how to fix it,&lt;/li&gt;
&lt;li&gt;connect it programmatically,&lt;/li&gt;
&lt;li&gt;summarize errors for long forms,&lt;/li&gt;
&lt;li&gt;move focus intentionally after failed submission.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;“Invalid input” is not a helpful error. It is a shrug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dialogs are traps unless designed carefully
&lt;/h2&gt;

&lt;p&gt;A modal dialog should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;move focus into the dialog when opened,&lt;/li&gt;
&lt;li&gt;trap focus while open,&lt;/li&gt;
&lt;li&gt;close with Escape when appropriate,&lt;/li&gt;
&lt;li&gt;return focus to the triggering element,&lt;/li&gt;
&lt;li&gt;have a clear accessible name,&lt;/li&gt;
&lt;li&gt;avoid background interaction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If that sounds like a lot, use a well-tested primitive. Dialogs are one of the places where “simple custom code” often becomes inaccessible custom code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not use color alone
&lt;/h2&gt;

&lt;p&gt;Color is useful. It should not be the only signal.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Required fields are red.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Required fields have text, an icon, and programmatic state.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For charts, statuses, validation, and alerts, combine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;text,&lt;/li&gt;
&lt;li&gt;shape,&lt;/li&gt;
&lt;li&gt;position,&lt;/li&gt;
&lt;li&gt;iconography,&lt;/li&gt;
&lt;li&gt;semantic markup.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automated tests are a floor
&lt;/h2&gt;

&lt;p&gt;Add accessibility checks to CI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&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;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AxeBuilder&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;@axe-core/playwright&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;page has no obvious accessibility violations&lt;/span&gt;&lt;span class="dl"&gt;"&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;page&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;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/settings&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;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AxeBuilder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;violations&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is good. It is not enough.&lt;/p&gt;

&lt;p&gt;Automated tools cannot fully judge whether the flow makes sense, whether focus movement feels logical, or whether the content is understandable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The human checklist
&lt;/h2&gt;

&lt;p&gt;Before release, test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Can the full flow be completed with keyboard only?&lt;/li&gt;
&lt;li&gt;[ ] Is focus always visible?&lt;/li&gt;
&lt;li&gt;[ ] Are headings meaningful and ordered?&lt;/li&gt;
&lt;li&gt;[ ] Are form labels explicit?&lt;/li&gt;
&lt;li&gt;[ ] Are errors helpful and connected to fields?&lt;/li&gt;
&lt;li&gt;[ ] Are dialogs focus-managed?&lt;/li&gt;
&lt;li&gt;[ ] Is color supported by another signal?&lt;/li&gt;
&lt;li&gt;[ ] Does the page make sense with CSS disabled?&lt;/li&gt;
&lt;li&gt;[ ] Does the page make sense with images unavailable?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Accessibility is not a separate layer you add after the “normal” product is done.&lt;/p&gt;

&lt;p&gt;It is part of the product being usable.&lt;/p&gt;

&lt;p&gt;A green automated score is a good start. A real user completing a real task without barriers is the goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CSS-Tricks, “HTTP Archive 2025 Web Almanac,” published January 16, 2026: &lt;a href="https://css-tricks.com/http-archive-2025-web-almanac/" rel="noopener noreferrer"&gt;https://css-tricks.com/http-archive-2025-web-almanac/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Syncfusion, “Frontend Development Trends 2026,” published April 28, 2026: &lt;a href="https://www.syncfusion.com/blogs/post/frontend-development-trends" rel="noopener noreferrer"&gt;https://www.syncfusion.com/blogs/post/frontend-development-trends&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MDN Web Docs, “Baseline compatibility”: &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks for reading.&lt;/p&gt;

&lt;p&gt;You can find me here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/johnnylemonny" rel="noopener noreferrer"&gt;https://github.com/johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/johnnylemonny"&gt;https://dev.to/johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>html</category>
      <category>frontend</category>
    </item>
    <item>
      <title>CSS Got Good While You Were Installing More Libraries</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Thu, 28 May 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/css-got-good-while-you-were-installing-more-libraries-dm1</link>
      <guid>https://dev.to/johnnylemonny/css-got-good-while-you-were-installing-more-libraries-dm1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Modern Web Development in 2026&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A practical series about building faster, cleaner, more maintainable web applications without chasing every shiny thing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A lot of frontend habits were formed when CSS was weaker.&lt;/p&gt;

&lt;p&gt;We reached for libraries because layout was painful, responsive components were awkward, browser support was uncertain, and the cascade felt like a haunted basement.&lt;/p&gt;

&lt;p&gt;That history is real.&lt;/p&gt;

&lt;p&gt;But modern CSS is not the same tool many developers learned five or ten years ago.&lt;/p&gt;

&lt;p&gt;CSS got good. Quietly. While everyone was arguing about JavaScript frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The new default: check the platform first
&lt;/h2&gt;

&lt;p&gt;Before installing a styling library, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can the platform solve this now?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Often, the answer is yes.&lt;/p&gt;

&lt;p&gt;Modern CSS gives us better primitives for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;responsive components,&lt;/li&gt;
&lt;li&gt;layout composition,&lt;/li&gt;
&lt;li&gt;cascade control,&lt;/li&gt;
&lt;li&gt;design tokens,&lt;/li&gt;
&lt;li&gt;theme switching,&lt;/li&gt;
&lt;li&gt;typography,&lt;/li&gt;
&lt;li&gt;state-based styling,&lt;/li&gt;
&lt;li&gt;fluid spacing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Libraries can still be useful. They should not be reflexes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Container queries change component design
&lt;/h2&gt;

&lt;p&gt;Viewport media queries answer this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How wide is the screen?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Container queries answer the more useful question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How much space does this component have?&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card-grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;container-type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@container&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;42rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.article-card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14rem&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&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;This makes components more portable. A card can adapt inside a sidebar, dashboard, modal, or full-width layout without pretending the viewport is the only context.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;:has()&lt;/code&gt; makes parent-aware styling practical
&lt;/h2&gt;

&lt;p&gt;For years, developers wanted a parent selector. Now we have a powerful version of it.&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="nc"&gt;.field&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:invalid&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-danger&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="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.card__media&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&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;Used carefully, &lt;code&gt;:has()&lt;/code&gt; can remove JavaScript that only exists to toggle classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cascade layers make CSS less fragile
&lt;/h2&gt;

&lt;p&gt;The cascade is not bad. Unmanaged cascade is bad.&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;@layer&lt;/span&gt; &lt;span class="n"&gt;reset&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="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--space-4&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="py"&gt;--radius-lg&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--radius-lg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--space-4&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;Layers let you define priority intentionally instead of relying on selector combat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subgrid fixes a real layout problem
&lt;/h2&gt;

&lt;p&gt;Nested layouts often need to align with parent tracks.&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="nc"&gt;.article-list&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;42rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.article-card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;subgrid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps create layouts that feel designed, not merely stacked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fluid type without a framework
&lt;/h2&gt;

&lt;p&gt;You can create responsive typography with plain CSS:&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;--step-0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clamp&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="m"&gt;0.96rem&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="m"&gt;0.2vw&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="py"&gt;--step-3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.75rem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1.25rem&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="m"&gt;2vw&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="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="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--step-3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.05&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&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="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--step-0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.7&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;No runtime. No package. No hydration. Just CSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Baseline thinking
&lt;/h2&gt;

&lt;p&gt;The modern question is not “Can I use this feature on my machine?”&lt;/p&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this feature supported well enough for my audience and fallback strategy?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Baseline helps make that decision more systematic, but it does not replace testing. You still need to check accessibility, usability, performance, and your actual user base.&lt;/p&gt;

&lt;h2&gt;
  
  
  The library decision checklist
&lt;/h2&gt;

&lt;p&gt;Before adding a styling dependency, ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Is the problem solved by modern CSS?&lt;/li&gt;
&lt;li&gt;[ ] Does the library add runtime JavaScript?&lt;/li&gt;
&lt;li&gt;[ ] Does it make accessibility easier or harder?&lt;/li&gt;
&lt;li&gt;[ ] Can the team debug the generated output?&lt;/li&gt;
&lt;li&gt;[ ] Does it work with our design tokens?&lt;/li&gt;
&lt;li&gt;[ ] Can we remove it later?&lt;/li&gt;
&lt;li&gt;[ ] Is the dependency worth the long-term surface area?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;CSS is not just the thing you write after the “real” engineering is done.&lt;/p&gt;

&lt;p&gt;It is a powerful layout and interaction language that now solves problems we used to outsource by default.&lt;/p&gt;

&lt;p&gt;Install libraries when they help. But give the platform a chance first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;web.dev, “Baseline”: &lt;a href="https://web.dev/baseline/" rel="noopener noreferrer"&gt;https://web.dev/baseline/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MDN Web Docs, “Baseline compatibility”: &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CSS-Tricks, “HTTP Archive 2025 Web Almanac,” published January 16, 2026: &lt;a href="https://css-tricks.com/http-archive-2025-web-almanac/" rel="noopener noreferrer"&gt;https://css-tricks.com/http-archive-2025-web-almanac/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks for reading.&lt;/p&gt;

&lt;p&gt;You can find me here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/johnnylemonny" rel="noopener noreferrer"&gt;https://github.com/johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/johnnylemonny"&gt;https://dev.to/johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>design</category>
    </item>
    <item>
      <title>TypeScript Won — Now Stop Using It Like Fancy JavaScript</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Tue, 26 May 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/typescript-won-now-stop-using-it-like-fancy-javascript-3hi0</link>
      <guid>https://dev.to/johnnylemonny/typescript-won-now-stop-using-it-like-fancy-javascript-3hi0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Modern Web Development in 2026&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A practical series about building faster, cleaner, more maintainable web applications without chasing every shiny thing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TypeScript won the argument.&lt;/p&gt;

&lt;p&gt;Most serious JavaScript codebases either use it already or are planning around it. The more interesting question is what we do after adoption.&lt;/p&gt;

&lt;p&gt;Because a lot of TypeScript code is still just JavaScript wearing a blazer.&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;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Technically TypeScript. Spiritually not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types should protect boundaries
&lt;/h2&gt;

&lt;p&gt;The best places to spend type effort are boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API input,&lt;/li&gt;
&lt;li&gt;API output,&lt;/li&gt;
&lt;li&gt;database records,&lt;/li&gt;
&lt;li&gt;form state,&lt;/li&gt;
&lt;li&gt;configuration,&lt;/li&gt;
&lt;li&gt;feature flags,&lt;/li&gt;
&lt;li&gt;permissions,&lt;/li&gt;
&lt;li&gt;domain events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Internal implementation types are useful. Boundary types are where bugs go to die.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replace vague shapes with domain language
&lt;/h2&gt;

&lt;p&gt;This is common:&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;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;status&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is better than nothing, but it leaves too much room.&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;type&lt;/span&gt; &lt;span class="nx"&gt;UserRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&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;editor&lt;/span&gt;&lt;span class="dl"&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;viewer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invited&lt;/span&gt;&lt;span class="dl"&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;active&lt;/span&gt;&lt;span class="dl"&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;suspended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserRole&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserStatus&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;Now invalid states have fewer places to hide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use branded types for dangerous strings
&lt;/h2&gt;

&lt;p&gt;Not every string is the same kind of string.&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;type&lt;/span&gt; &lt;span class="nx"&gt;Brand&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;__brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Brand&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserId&lt;/span&gt;&lt;span class="dl"&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;type&lt;/span&gt; &lt;span class="nx"&gt;OrgId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Brand&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OrgId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&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;Now this mistake becomes harder:&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;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orgId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OrgId&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="nx"&gt;UserId&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;A plain string can come from anywhere. A branded string says, “This value passed through a specific gate.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Prefer discriminated unions over boolean soup
&lt;/h2&gt;

&lt;p&gt;Boolean-heavy state is where UI bugs breed.&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;type&lt;/span&gt; &lt;span class="nx"&gt;RequestState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows nonsense:&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="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&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;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;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a union:&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;type&lt;/span&gt; &lt;span class="nx"&gt;RequestState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&lt;/span&gt;&lt;span class="dl"&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;message&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the impossible states are actually impossible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate runtime data
&lt;/h2&gt;

&lt;p&gt;TypeScript does not validate JSON at runtime.&lt;/p&gt;

&lt;p&gt;This is one of the most expensive misunderstandings in web development.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;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="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That line does not make the response a &lt;code&gt;User&lt;/code&gt;. It makes the compiler quiet.&lt;/p&gt;

&lt;p&gt;Use runtime validation at external boundaries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt; &lt;span class="o"&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;id&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="na"&gt;role&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;enum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&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;editor&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;viewer&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invited&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;active&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;suspended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now TypeScript and runtime reality are connected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use &lt;code&gt;satisfies&lt;/code&gt; for configuration
&lt;/h2&gt;

&lt;p&gt;Configuration should be checked without losing literal types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;home&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="na"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="o"&gt;&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;This catches invalid values while preserving useful inference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid type theater
&lt;/h2&gt;

&lt;p&gt;Some types add noise but not safety.&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;type&lt;/span&gt; &lt;span class="nx"&gt;StringOrNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ObjectMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&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;These can be valid in rare cases, but often they are placeholders for decisions nobody made.&lt;/p&gt;

&lt;p&gt;Good TypeScript is not more TypeScript. Good TypeScript is better constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical checklist
&lt;/h2&gt;

&lt;p&gt;Use this before merging TypeScript-heavy changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Are external inputs validated at runtime?&lt;/li&gt;
&lt;li&gt;[ ] Are domain concepts named explicitly?&lt;/li&gt;
&lt;li&gt;[ ] Are impossible UI states impossible?&lt;/li&gt;
&lt;li&gt;[ ] Are IDs and tokens distinguishable?&lt;/li&gt;
&lt;li&gt;[ ] Are &lt;code&gt;any&lt;/code&gt; and unsafe assertions isolated?&lt;/li&gt;
&lt;li&gt;[ ] Can a new developer understand the model from the types?&lt;/li&gt;
&lt;li&gt;[ ] Do the types reduce tests you would otherwise need?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;TypeScript is not valuable because it makes JavaScript look professional.&lt;/p&gt;

&lt;p&gt;It is valuable because it lets you encode decisions before those decisions become bugs.&lt;/p&gt;

&lt;p&gt;If your types do not protect boundaries, model the domain, or remove impossible states, you are leaving most of the value on the table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;InfoQ, “State of JavaScript 2025: Survey Reveals a Maturing Ecosystem with TypeScript Cementing Dominance,” published March 20, 2026: &lt;a href="https://www.infoq.com/news/2026/03/state-of-js-survey-2025/" rel="noopener noreferrer"&gt;https://www.infoq.com/news/2026/03/state-of-js-survey-2025/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Syncfusion, “Frontend Development Trends 2026,” published April 28, 2026: &lt;a href="https://www.syncfusion.com/blogs/post/frontend-development-trends" rel="noopener noreferrer"&gt;https://www.syncfusion.com/blogs/post/frontend-development-trends&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks for reading.&lt;/p&gt;

&lt;p&gt;You can find me here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/johnnylemonny" rel="noopener noreferrer"&gt;https://github.com/johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/johnnylemonny"&gt;https://dev.to/johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Cabal for Android: My First Native Kotlin P2P Chat App Reaches Its First Early Version</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Tue, 26 May 2026 06:30:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/cabal-for-android-my-first-native-kotlin-p2p-chat-app-reaches-its-first-early-version-1n64</link>
      <guid>https://dev.to/johnnylemonny/cabal-for-android-my-first-native-kotlin-p2p-chat-app-reaches-its-first-early-version-1n64</guid>
      <description>&lt;p&gt;A few weeks ago, I wrote about working on &lt;strong&gt;Cabal v3&lt;/strong&gt;, a modern peer-to-peer chat app for Android, and how I started by exploring a React Native direction.&lt;/p&gt;

&lt;p&gt;Later, I also wrote about how I started learning &lt;strong&gt;Kotlin&lt;/strong&gt; by building a real Android app instead of only reading tutorials.&lt;/p&gt;

&lt;p&gt;This post is the continuation of that series.&lt;/p&gt;

&lt;p&gt;Today, I’m happy to share that the first early version of &lt;strong&gt;Cabal for Android&lt;/strong&gt; is now available.&lt;/p&gt;

&lt;p&gt;GitHub repository:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/johnnylemonny/cabal-android" rel="noopener noreferrer"&gt;https://github.com/johnnylemonny/cabal-android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An early version is also available to download from the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Cabal for Android?
&lt;/h2&gt;

&lt;p&gt;Cabal for Android is my attempt to build a modern Android client for Cabal as a native Kotlin application.&lt;/p&gt;

&lt;p&gt;The idea is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a peer-to-peer chat app for Android, built with modern native Android development in mind.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This project started as an experiment, but it quickly became something more serious for me. It became a way to learn Kotlin, understand Android development better, and explore how decentralized communication can feel on mobile.&lt;/p&gt;

&lt;h2&gt;
  
  
  From React Native exploration to native Kotlin
&lt;/h2&gt;

&lt;p&gt;In the first post of this series, I wrote about reviving a P2P mobile chat app idea and experimenting with Cabal on Android.&lt;/p&gt;

&lt;p&gt;At that point, I was thinking about the project from a React Native perspective.&lt;/p&gt;

&lt;p&gt;That was useful because it helped me understand the shape of the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the UI could look like,&lt;/li&gt;
&lt;li&gt;how the chat flow should feel,&lt;/li&gt;
&lt;li&gt;what kind of mobile experience I wanted,&lt;/li&gt;
&lt;li&gt;and how much work would be involved in bringing a P2P chat app back to life on Android.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But after spending more time with the project, I decided to move deeper into native Android development.&lt;/p&gt;

&lt;p&gt;That decision led me to Kotlin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Kotlin?
&lt;/h2&gt;

&lt;p&gt;Kotlin had been on my list for a long time.&lt;/p&gt;

&lt;p&gt;I had read about it before. I had seen examples. I understood the basic syntax. But I never really learned it properly because I was missing one important thing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a real project.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cabal became that project.&lt;/p&gt;

&lt;p&gt;Instead of learning Kotlin in isolation, I learned it by building something that had real screens, real state, real problems, and real trade-offs.&lt;/p&gt;

&lt;p&gt;That changed everything.&lt;/p&gt;

&lt;p&gt;Kotlin stopped being just a list of language features and became a tool I used every day to move the app forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is included in this first version?
&lt;/h2&gt;

&lt;p&gt;This is still an early version, but it is an important milestone.&lt;/p&gt;

&lt;p&gt;The app is now at the point where it feels like a real native Android project instead of just an idea or experiment.&lt;/p&gt;

&lt;p&gt;The first version focuses on the foundation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;native Android structure,&lt;/li&gt;
&lt;li&gt;Kotlin-based implementation,&lt;/li&gt;
&lt;li&gt;a modern mobile app direction,&lt;/li&gt;
&lt;li&gt;Cabal-related chat experience,&lt;/li&gt;
&lt;li&gt;early downloadable build,&lt;/li&gt;
&lt;li&gt;and a codebase that can now evolve further.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is not perfect yet.&lt;/p&gt;

&lt;p&gt;It is not “finished” in the final-product sense.&lt;/p&gt;

&lt;p&gt;But it is finished in the most important early-stage sense:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the project exists, runs, can be tested, and has a real direction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That feels like a big step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned while building it
&lt;/h2&gt;

&lt;p&gt;Building this first version taught me much more than I expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Real apps teach faster than tutorials
&lt;/h3&gt;

&lt;p&gt;Tutorials are useful, but they usually have clean examples and predictable problems.&lt;/p&gt;

&lt;p&gt;Real apps are different.&lt;/p&gt;

&lt;p&gt;When building Cabal for Android, I had to make decisions about structure, state, screens, naming, data flow, and how to keep the app understandable as it grew.&lt;/p&gt;

&lt;p&gt;That kind of learning is harder, but also much more valuable.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Kotlin makes Android development feel focused
&lt;/h3&gt;

&lt;p&gt;One thing I started to appreciate is how Kotlin encourages more intentional code.&lt;/p&gt;

&lt;p&gt;Null safety, data classes, immutability, and concise syntax all helped me think more clearly about the app.&lt;/p&gt;

&lt;p&gt;At first, some parts slowed me down. But over time, those same features made the project feel safer and easier to reason about.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Native Android development has its own rhythm
&lt;/h3&gt;

&lt;p&gt;Coming from other environments, native Android development requires a different mindset.&lt;/p&gt;

&lt;p&gt;You are not only learning Kotlin.&lt;/p&gt;

&lt;p&gt;You are also learning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android project structure,&lt;/li&gt;
&lt;li&gt;lifecycle concepts,&lt;/li&gt;
&lt;li&gt;UI patterns,&lt;/li&gt;
&lt;li&gt;state handling,&lt;/li&gt;
&lt;li&gt;Gradle,&lt;/li&gt;
&lt;li&gt;app packaging,&lt;/li&gt;
&lt;li&gt;and how all of these pieces fit together.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was challenging, but also one of the best parts of the process.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Small milestones matter
&lt;/h3&gt;

&lt;p&gt;This version is early, but shipping it matters.&lt;/p&gt;

&lt;p&gt;It is easy to keep waiting until everything is perfect.&lt;/p&gt;

&lt;p&gt;But open-source projects grow better when they are visible early.&lt;/p&gt;

&lt;p&gt;Putting this first version out there gives the project a real starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this project matters to me
&lt;/h2&gt;

&lt;p&gt;Cabal for Android sits at the intersection of a few things I care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mobile development,&lt;/li&gt;
&lt;li&gt;Kotlin,&lt;/li&gt;
&lt;li&gt;Android,&lt;/li&gt;
&lt;li&gt;open source,&lt;/li&gt;
&lt;li&gt;peer-to-peer communication,&lt;/li&gt;
&lt;li&gt;and learning by building.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I like projects that are practical but also a little experimental.&lt;/p&gt;

&lt;p&gt;A P2P chat app is exactly that kind of project.&lt;/p&gt;

&lt;p&gt;It is not just another CRUD app. It forces you to think about networking, identity, local-first experiences, mobile constraints, and how users communicate without depending entirely on centralized infrastructure.&lt;/p&gt;

&lt;p&gt;That makes it a fun and meaningful project to work on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repository and download
&lt;/h2&gt;

&lt;p&gt;The project is available here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/johnnylemonny/cabal-android" rel="noopener noreferrer"&gt;https://github.com/johnnylemonny/cabal-android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also an early downloadable version available from the repository.&lt;/p&gt;

&lt;p&gt;If you are interested in Kotlin, Android, peer-to-peer apps, or open-source mobile development, feel free to check it out.&lt;/p&gt;

&lt;p&gt;Feedback, ideas, and contributions are welcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes next?
&lt;/h2&gt;

&lt;p&gt;This first version is only the beginning.&lt;/p&gt;

&lt;p&gt;Next, I want to continue improving the app step by step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;polish the UI,&lt;/li&gt;
&lt;li&gt;improve the chat experience,&lt;/li&gt;
&lt;li&gt;clean up the architecture,&lt;/li&gt;
&lt;li&gt;test more edge cases,&lt;/li&gt;
&lt;li&gt;improve stability,&lt;/li&gt;
&lt;li&gt;and continue learning Kotlin through real development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also want to keep writing about the process because documenting the journey helps me understand what I’m learning.&lt;/p&gt;

&lt;p&gt;And maybe it helps someone else too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;This project started as an experiment.&lt;/p&gt;

&lt;p&gt;Then it became a Kotlin learning project.&lt;/p&gt;

&lt;p&gt;Now it is becoming a real native Android app.&lt;/p&gt;

&lt;p&gt;That progression has been very motivating.&lt;/p&gt;

&lt;p&gt;The biggest lesson so far is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to learn a technology deeply, build something real with it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cabal for Android gave me a reason to learn Kotlin properly.&lt;/p&gt;

&lt;p&gt;And now the first early version is here.&lt;/p&gt;

&lt;p&gt;Thanks for reading — and if you try the app or look through the code, I’d love to hear what you think.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>android</category>
      <category>opensource</category>
      <category>p2p</category>
    </item>
    <item>
      <title>Next.js Caching Is Hard Because You’re Thinking About It Too Late</title>
      <dc:creator>𝗝𝗼𝗵𝗻</dc:creator>
      <pubDate>Thu, 21 May 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/johnnylemonny/nextjs-caching-is-hard-because-youre-thinking-about-it-too-late-586m</link>
      <guid>https://dev.to/johnnylemonny/nextjs-caching-is-hard-because-youre-thinking-about-it-too-late-586m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Modern Web Development in 2026&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A practical series about building faster, cleaner, more maintainable web applications without chasing every shiny thing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next.js caching is not hard because caching is mysterious.&lt;/p&gt;

&lt;p&gt;It is hard because teams often decide what the user should see, build the feature, ship the route, and only then ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Wait, should this be cached?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By that point, caching feels like a trap. Static or dynamic? Revalidate or no-store? Tag invalidation? Server Actions? Partial rendering? Why did this page update locally but not in production?&lt;/p&gt;

&lt;p&gt;The problem started earlier.&lt;/p&gt;

&lt;p&gt;Caching is not a setting. It is a product decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with freshness
&lt;/h2&gt;

&lt;p&gt;Before writing code, classify the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Always fresh        account balance, auth state, checkout price
Fresh enough        inventory count, dashboard cards, notifications
Rarely changes      marketing copy, docs navigation, pricing page layout
Versioned           blog posts, changelog entries, release notes
User-triggered      form result, optimistic mutation, saved settings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each category deserves a different strategy.&lt;/p&gt;

&lt;p&gt;If you do not define freshness, the framework cannot guess your intent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The user does not care about your cache
&lt;/h2&gt;

&lt;p&gt;Users care about expectations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“I changed my profile; I should see it now.”&lt;/li&gt;
&lt;li&gt;“I published a post; the public page should update soon.”&lt;/li&gt;
&lt;li&gt;“I added an item to cart; the total should be correct.”&lt;/li&gt;
&lt;li&gt;“I opened docs; they should load instantly.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those expectations map directly to caching behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache by boundary, not by hope
&lt;/h2&gt;

&lt;p&gt;A page usually contains mixed data.&lt;/p&gt;

&lt;p&gt;Example product page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;product title: rarely changes,&lt;/li&gt;
&lt;li&gt;price: may change,&lt;/li&gt;
&lt;li&gt;inventory: fresh enough,&lt;/li&gt;
&lt;li&gt;recommendations: personalized,&lt;/li&gt;
&lt;li&gt;reviews: revalidated periodically,&lt;/li&gt;
&lt;li&gt;cart state: user-specific.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you cache the entire page as one unit, one dynamic section can make the whole route harder to reason about.&lt;/p&gt;

&lt;p&gt;Instead, design boundaries:&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;export&lt;/span&gt; &lt;span class="k"&gt;default&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;ProductPage&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="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;main&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;ProductShell&lt;/span&gt; &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&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;LivePurchaseBox&lt;/span&gt; &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&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;Recommendations&lt;/span&gt; &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&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;main&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;p&gt;Then each section can have its own freshness model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make invalidation boring
&lt;/h2&gt;

&lt;p&gt;Invalidation should be obvious from the mutation.&lt;/p&gt;

&lt;p&gt;Bad mutation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;updateProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better mutation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;updateProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;invalidateProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;invalidateProductList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even better: centralize the policy so developers do not remember tags by hand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;invalidateProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productId&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="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`product:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products:list&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;A cache strategy nobody can remember is not a strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid accidental personalization leaks
&lt;/h2&gt;

&lt;p&gt;Caching becomes dangerous when user-specific data slips into shared output.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;user names in cached navigation,&lt;/li&gt;
&lt;li&gt;role-specific actions in shared HTML,&lt;/li&gt;
&lt;li&gt;personalized recommendations in static shells,&lt;/li&gt;
&lt;li&gt;auth-only pricing mixed with public product data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple rule helps:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Public data can be shared. User data needs a user boundary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If a component depends on cookies, headers, session, or permissions, treat it differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use loading states intentionally
&lt;/h2&gt;

&lt;p&gt;Partial rendering and streaming are powerful because they let you show stable UI while dynamic sections load.&lt;/p&gt;

&lt;p&gt;But a loading skeleton is not a substitute for product thinking.&lt;/p&gt;

&lt;p&gt;Good skeleton:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;preserves layout,&lt;/li&gt;
&lt;li&gt;communicates progress,&lt;/li&gt;
&lt;li&gt;appears only where delay is expected,&lt;/li&gt;
&lt;li&gt;does not cause content to jump.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bad skeleton:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;flashes for 80ms,&lt;/li&gt;
&lt;li&gt;shifts the layout,&lt;/li&gt;
&lt;li&gt;appears everywhere,&lt;/li&gt;
&lt;li&gt;hides the fact that the data model is too slow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Debugging questions
&lt;/h2&gt;

&lt;p&gt;When a Next.js route behaves strangely, I use this checklist:&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;## Caching debug checklist&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Is this route expected to be static, dynamic, or mixed?
&lt;span class="p"&gt;-&lt;/span&gt; Which data must be fresh for every request?
&lt;span class="p"&gt;-&lt;/span&gt; Which data can be cached safely?
&lt;span class="p"&gt;-&lt;/span&gt; Is any user-specific data crossing a shared cache boundary?
&lt;span class="p"&gt;-&lt;/span&gt; What event invalidates this data?
&lt;span class="p"&gt;-&lt;/span&gt; Does the mutation revalidate the exact thing the user expects?
&lt;span class="p"&gt;-&lt;/span&gt; Is the loading state masking an architecture problem?
&lt;span class="p"&gt;-&lt;/span&gt; Can the behavior be explained in one paragraph?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last question matters. If nobody on the team can explain the caching behavior simply, production will explain it for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model
&lt;/h2&gt;

&lt;p&gt;Think of caching as a conversation between three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data truth&lt;/strong&gt; — where the correct data lives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User expectation&lt;/strong&gt; — when the user expects to see changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendering boundary&lt;/strong&gt; — where the UI can safely reuse work.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When those three agree, caching feels boring.&lt;/p&gt;

&lt;p&gt;When they disagree, caching feels haunted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Next.js caching is not something to sprinkle on a finished route.&lt;/p&gt;

&lt;p&gt;It belongs in the first design conversation.&lt;/p&gt;

&lt;p&gt;Decide freshness early. Draw boundaries early. Name invalidation early.&lt;/p&gt;

&lt;p&gt;Your future self will spend less time asking why the page is stale and more time building things users actually notice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next.js, “Next.js 16,” published October 21, 2025: &lt;a href="https://nextjs.org/blog/next-16" rel="noopener noreferrer"&gt;https://nextjs.org/blog/next-16&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;InfoWorld, “Next.js 16 features explicit caching, AI-powered debugging,” published October 24, 2025: &lt;a href="https://www.infoworld.com/article/4078213/next-js-16-features-explicit-caching-ai-powered-debugging.html" rel="noopener noreferrer"&gt;https://www.infoworld.com/article/4078213/next-js-16-features-explicit-caching-ai-powered-debugging.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks for reading.&lt;/p&gt;

&lt;p&gt;You can find me here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/johnnylemonny" rel="noopener noreferrer"&gt;https://github.com/johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/johnnylemonny"&gt;https://dev.to/johnnylemonny&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
