<?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: FocusReactive | Headless CMS Agency</title>
    <description>The latest articles on DEV Community by FocusReactive | Headless CMS Agency (@focusreactive).</description>
    <link>https://dev.to/focusreactive</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F7833%2Fc570dc76-be10-4541-a24b-c091d92fc6fe.png</url>
      <title>DEV Community: FocusReactive | Headless CMS Agency</title>
      <link>https://dev.to/focusreactive</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/focusreactive"/>
    <language>en</language>
    <item>
      <title>Google Tag Manager Loading Strategies in Next.js</title>
      <dc:creator>Sergey Labut</dc:creator>
      <pubDate>Fri, 13 Feb 2026 09:51:06 +0000</pubDate>
      <link>https://dev.to/focusreactive/google-tag-manager-loading-strategies-in-nextjs-3d0b</link>
      <guid>https://dev.to/focusreactive/google-tag-manager-loading-strategies-in-nextjs-3d0b</guid>
      <description>&lt;p&gt;&lt;strong&gt;Performance, Analytics Accuracy, and Risk-Aware Implementation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google Tag Manager (GTM) can significantly affect Next.js apps. Choosing the right loading strategy requires balancing &lt;strong&gt;performance&lt;/strong&gt;, &lt;strong&gt;tracking reliability&lt;/strong&gt;, and &lt;strong&gt;implementation risk&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This guide covers &lt;strong&gt;seven strategies&lt;/strong&gt;, with &lt;strong&gt;performance / analytics / complexity &amp;amp; risk&lt;/strong&gt; explained for each, including common mistakes and implementation examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why GTM Loading Matters in Next.js
&lt;/h2&gt;

&lt;p&gt;Next.js applications differ from traditional websites in important ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pages are server-rendered and then hydrated on the client&lt;/li&gt;
&lt;li&gt;JavaScript execution during hydration affects interaction metrics (&lt;strong&gt;INP&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Client-side navigation does not reload the page&lt;/li&gt;
&lt;li&gt;Page views must be tracked manually on route changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of this, GTM loading strategy directly affects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Core Web Vitals&lt;/strong&gt; (especially INP and LCP)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hydration speed and responsiveness&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Analytics accuracy and attribution&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Balanced Approach – After-Interactive Loading (Recommended Default)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Performance:&lt;/strong&gt; Good&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Analytics:&lt;/strong&gt; High&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Complexity / Risk:&lt;/strong&gt; Low&lt;/p&gt;
&lt;h3&gt;
  
  
  What this means
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;GTM loads after the page becomes interactive using &lt;code&gt;strategy="afterInteractive"&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Hydration is not blocked, but GTM may execute while hydration is still finishing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Common mistakes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Forgetting SPA page view tracking&lt;/li&gt;
&lt;li&gt;Assuming &lt;code&gt;afterInteractive&lt;/code&gt; alone guarantees good INP&lt;/li&gt;
&lt;li&gt;Leaving GTM’s default page view trigger enabled and causing duplicates
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Script&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;next/script&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;GTM_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_GTM_ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GTM&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Script&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gtm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;afterInteractive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
        &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
          // Ensure dataLayer exists before GTM loads
          window.dataLayer = window.dataLayer || [];

          (function(w,d,s,l,i){
            w[l]=w[l]||[];
            w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});
            var f=d.getElementsByTagName(s)[0],
                j=d.createElement(s),
                dl=l!='dataLayer'?'&amp;amp;l='+l:'';
            j.async=true;
            j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
            f.parentNode.insertBefore(j,f);
          })(window,document,'script','dataLayer','&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;GTM_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;');
        `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;SPA page view tracking — required&lt;br&gt;
Because Next.js uses client-side routing, page views must be sent manually on route changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If you do this, disable GTM’s default Page View trigger to avoid duplicates.&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;// SPA page view tracking — Pages Router&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&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;next/router&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;usePageViews&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRouteChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataLayer&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="na"&gt;event&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_view&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;page_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;page_location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;routeChangeComplete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleRouteChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;routeChangeComplete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleRouteChange&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;router&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SPA page view tracking — App Router&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;usePathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useSearchParams&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;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PageViewTracker&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;pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePathname&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;searchParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSearchParams&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pagePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataLayer&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="na"&gt;event&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_view&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;page_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pagePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;page_location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&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="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Max Tracking – Early Loading (Before-Interactive)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Moderate / Risky&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt;: Maximum&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity / Risk&lt;/strong&gt;: Low&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What this means
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;GTM loads before React hydration starts using beforeInteractive.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Script&lt;/span&gt; &lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;beforeInteractive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://www.googletagmanager.com/gtm.js?id=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;GTM_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Common mistakes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;INP regressions caused by long GTM tasks&lt;/li&gt;
&lt;li&gt;Duplicate page views when default GTM page view triggers are combined with SPA tracking&lt;/li&gt;
&lt;li&gt;Assuming “early load” only affects LCP (INP is usually the real casualty)&lt;/li&gt;
&lt;li&gt;Letting marketing add heavy tags without performance review&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When to use
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Marketing-heavy pages&lt;/li&gt;
&lt;li&gt;Conversion funnels where attribution accuracy is critical&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Performance-First – Lazy Loading (After Page Fully Loads)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Very Good&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt;: Medium&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity / Risk&lt;/strong&gt;: Low&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What this means
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;GTM loads only after the browser load event.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Script&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gtm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lazyOnload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://www.googletagmanager.com/gtm.js?id=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;GTM_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Common mistakes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Assuming Lighthouse ignores GTM entirely&lt;/li&gt;
&lt;li&gt;Missing page views from short sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When to use
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Content-heavy sites&lt;/li&gt;
&lt;li&gt;SEO-driven pages where analytics is helpful but not critical&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Extreme Performance – Interaction-Based Loading with Event Buffering
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Excellent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt;: Medium–High&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity / Risk&lt;/strong&gt;: Medium&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What this means
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;GTM loads only after user interaction. Important events are buffered until GTM is ready.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common mistakes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Users who never interact are not tracked&lt;/li&gt;
&lt;li&gt;Event buffer flushed too late or never&lt;/li&gt;
&lt;li&gt;Overengineering simple setups
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example buffering logic&lt;/span&gt;
&lt;span class="c1"&gt;// Initialize dataLayer early&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataLayer&lt;/span&gt; &lt;span class="o"&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;bufferedEvents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&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="c1"&gt;// Track events before GTM is ready&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;trackEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gtmReady&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bufferedEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Call this when GTM finishes loading&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;onGtmReady&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bufferedEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gtmReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Conditional Loading – Consent, Region, or Route-Based
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Good&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt;: Medium&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity / Risk&lt;/strong&gt;: Medium–High&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What this means
&lt;/h3&gt;

&lt;p&gt;GTM is loaded only if certain conditions are met (for example, user consent).&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hasConsent&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GTM&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;h3&gt;
  
  
  Common mistakes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Inconsistent analytics across regions&lt;/li&gt;
&lt;li&gt;Consent state not persisted correctly&lt;/li&gt;
&lt;li&gt;Forgetting to update rules for new routes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When to use
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;GDPR-heavy environments&lt;/li&gt;
&lt;li&gt;Multi-region or multi-brand sites&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Server-Side GTM – High Reliability, High Complexity
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Good&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt;: Very High&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity / Risk&lt;/strong&gt;: High&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What this means
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The browser sends events to your server, which forwards them to GTM and analytics tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common mistakes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Poor client/server event parity&lt;/li&gt;
&lt;li&gt;Added latency without batching&lt;/li&gt;
&lt;li&gt;Underestimating maintenance cost&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When to use
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;High-traffic applications&lt;/li&gt;
&lt;li&gt;Long-term analytics infrastructure&lt;/li&gt;
&lt;li&gt;The user's browser extensions are blocking analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Web Worker GTM (Partytown) – Maximum Frontend Performance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Excellent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt;: High&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity / Risk&lt;/strong&gt;: High&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What this means
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;GTM runs in a Web Worker using Partytown, keeping heavy scripts off the main thread.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common mistakes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;DOM-dependent tags silently failing&lt;/li&gt;
&lt;li&gt;Missing forwarded APIs&lt;/li&gt;
&lt;li&gt;Difficult debugging
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Partytown&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;@builder.io/partytown/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Script&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;next/script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Partytown&lt;/span&gt; &lt;span class="nx"&gt;forward&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dataLayer.push&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Script&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/partytown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://www.googletagmanager.com/gtm.js?id=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;GTM_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or just&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://www.googletagmanager.com/gtm.js?id=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;GTM_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;worker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Recommendations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Default choice&lt;/strong&gt;: After-Interactive loading + manual SPA page views&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maximum analytics reliability&lt;/strong&gt;: Early loading or Server-Side GTM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extreme performance&lt;/strong&gt;: Interaction-based loading with buffering or Partytown&lt;/li&gt;
&lt;li&gt;Regularly audit GTM tags — loading strategy alone won’t fix heavy scripts&lt;/li&gt;
&lt;li&gt;Always validate SPA tracking when using the App Router&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Performance Impact&lt;/th&gt;
&lt;th&gt;Tracking Reliability&lt;/th&gt;
&lt;th&gt;Complexity&lt;/th&gt;
&lt;th&gt;Recommended For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;After Interactive (Recommended Default)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;High (manual SPA page views required)&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Most Next.js apps; balanced performance &amp;amp; analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Before Interactive (Early Load)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Marketing-heavy pages; critical attribution tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lazy Onload (After Page Fully Loads)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very Good&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Content-focused or SEO-driven pages; analytics not critical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Interaction-Based Load&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Blogs or informational pages; extreme performance priority&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Interaction with Event Buffering&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium-High&lt;/td&gt;
&lt;td&gt;Performance-first sites needing reliable early tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Conditional Load&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Medium-High&lt;/td&gt;
&lt;td&gt;GDPR-heavy, multi-region, or multi-brand setups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Server-Side GTM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High-traffic apps; long-term analytics &amp;amp; reliability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web Worker (Partytown)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Performance-critical sites; heavy third-party scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>analytics</category>
      <category>nextjs</category>
      <category>performance</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Automating your content with Sanity's Agent Actions, Functions &amp; Blueprints</title>
      <dc:creator>Eugene Boruhov</dc:creator>
      <pubDate>Mon, 18 Aug 2025 17:38:07 +0000</pubDate>
      <link>https://dev.to/focusreactive/automating-your-content-with-sanitys-agent-actions-functions-blueprints-59fg</link>
      <guid>https://dev.to/focusreactive/automating-your-content-with-sanitys-agent-actions-functions-blueprints-59fg</guid>
      <description>&lt;p&gt;For a long time, we collectively treated the CMS as a "content store" - a convenient database with a  UI where non-developers could edit text and images without, as we’d say, a pain in the ass. Its job was to hold things.&lt;/p&gt;

&lt;p&gt;But over the past few years, Sanity has been aggressively pushing the boundaries of that definition. They transitioned from a simple content store into a true &lt;strong&gt;Content Operating System&lt;/strong&gt;. It became a hub for structured data you can model, query, and connect in powerful new ways.&lt;/p&gt;

&lt;p&gt;Yet, for all this progress, we as developers still hit a ceiling. When it came to a crucial part of the modern stack, automation, we had to look elsewhere. We found ourselves reaching for Vercel or Netlify functions to handle tasks that felt like they should belong inside Sanity. We needed to enrich content on publish, trigger a validation workflow or sync data with another service.&lt;/p&gt;

&lt;p&gt;This approach worked, but it always felt like a workaround. It created a divide, forcing us to manage fragmented architectures and spread authentication tokens across platforms. Our logic lived in one place, and our content in another.&lt;/p&gt;

&lt;p&gt;With the &lt;a href="https://www.sanity.io/blog/what-s-new-june-2025" rel="noopener noreferrer"&gt;Spring Release&lt;/a&gt;, that is no longer the case. Sanity has finally delivered the missing piece. The introduction of native AI and serverless capabilities means the platform is no longer just a sophisticated content store - it has become a truly mature &lt;strong&gt;Content Engine&lt;/strong&gt;. The logic and the content can now live together, closing the gap and fundamentally changing what's possible within a single, unified system.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI &amp;amp; Automation Inside Sanity
&lt;/h2&gt;

&lt;p&gt;So, what powers this new Content Engine? Sanity has delivered a trio of interconnected features that together create a complete and native ecosystem for automation. While still in their early stages, they already form a powerful foundation.&lt;/p&gt;

&lt;p&gt;Think of it as a complete toolkit with three core components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Agent Actions (AI brains).&lt;/strong&gt; This is the intelligence layer. Agent Actions are schema-aware AI instructions that can programmatically generate, transform, and translate your content. They aren't just simple text prompts - they understand your content models, which allows for incredibly precise and structured results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Functions (automation engine).&lt;/strong&gt; This is the serverless power we've been waiting for. Functions are event-driven pieces of code that live right inside your Sanity project and react to content changes. Triggered by content operations like ⁠publish, ⁠create, or ⁠delete, these functions spring into action, running your code and eliminating the need for external webhooks or authentication boilerplate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blueprints (infrastructure scaffolding).&lt;/strong&gt; This is how you manage your new serverless capabilities using an infrastructure-as-code approach. Blueprints allow you to declaratively define, configure, and deploy your Functions, ensuring your automation setup is version-controlled, repeatable, and easy to manage from the command line.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The true power of this toolkit lies in how these components work together. You can use an &lt;strong&gt;Agent Action&lt;/strong&gt; to define an AI task, then invoke it from a &lt;strong&gt;Function&lt;/strong&gt; that triggers when a document is published, all managed and deployed via a &lt;strong&gt;Blueprint&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the integrated system that ends the workarounds. Let's break it down, starting with the AI brains of the operation: Agent Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent Actions
&lt;/h2&gt;

&lt;p&gt;The core of Sanity's new AI capabilities is powered by &lt;strong&gt;Agent Actions&lt;/strong&gt;. Think of them as an intelligent, schema-aware layer that sits on top of your content. They know what a "blog post" is in your project, what fields it has, and how a "product" might reference a "category." This awareness allows them to perform tasks with a level of precision that was previously impossible without complex, hand-written code.&lt;/p&gt;

&lt;p&gt;The Agent Actions are broken down into four distinct capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generate:&lt;/strong&gt; This is your creative engine. It goes beyond just text, allowing you to create entire documents from scratch, complete with structured data and even &lt;strong&gt;generated images&lt;/strong&gt;. It's perfect for drafting a blog post from a title, populating a product description, or creating visual assets that match your content's context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transform:&lt;/strong&gt; This is your intelligent editor. Instead of crude find-and-replace operations, Transform can modify existing documents with nuance. Use it to change an article's tone from formal to casual, summarize a long passage into a concise description, or update fields while preserving the integrity of the rest of the document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Translate:&lt;/strong&gt; Purpose-built for localization, this action handles both document-level and field-level translation. It's smart enough to protect brand names, technical terms, or other phrases you define, ensuring your core messaging remains consistent across languages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt:&lt;/strong&gt; This is your direct line to an LLM, but with your Sanity content as the built-in context. It allows you to ask questions, analyze data, or run custom instructions against your documents without having to pipe the content to an external service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These powerful actions are already being integrated across the Sanity ecosystem. The recently introduced &lt;a href="https://www.sanity.io/blog/introducing-sanity-model-context-protocol-server" rel="noopener noreferrer"&gt;&lt;strong&gt;Sanity MCP&lt;/strong&gt;&lt;/a&gt;, which allows AI coding assistants to interact with Sanity projects, uses this new Agent Actions API under the hood.&lt;/p&gt;

&lt;p&gt;For developers, getting started is straightforward. The actions are exposed as a new dedicated scope within the familiar &lt;code&gt;@sanity/client&lt;/code&gt;, making them easy to call from anywhere you can run JavaScript. But how do we put them on autopilot? For that, we need an engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions &amp;amp; Blueprints
&lt;/h2&gt;

&lt;p&gt;An AI brain is powerful, but its true potential is unlocked when it can act on its own. This is where &lt;strong&gt;Sanity Functions&lt;/strong&gt; come in - the serverless engine we've been waiting for. This is the feature that finally allows us to stop outsourcing our automation logic to external platforms.&lt;/p&gt;

&lt;p&gt;Functions are event-driven, single-purpose pieces of code that live directly within your Sanity project. They respond to content changes, such as publish, update, or delete - and execute your logic right on Sanity's infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Functions CLI
&lt;/h3&gt;

&lt;p&gt;Sanity has built a complete local-first workflow around Functions. The CLI provides a robust development environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;sanity functions dev&lt;/code&gt; to run a local emulator for real-time development&lt;/li&gt;
&lt;li&gt;Simulate trigger events with &lt;code&gt;⁠sanity functions test&lt;/code&gt;. It lets you invoke your function locally with a mock payload by passing either a local JSON file or the ID of a document in your dataset&lt;/li&gt;
&lt;li&gt;When you need to debug a deployed function, you can stream its logs directly to your terminal with &lt;code&gt;sanity functions logs&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Automation with GROQ Delta Functions
&lt;/h3&gt;

&lt;p&gt;What makes Sanity Functions particularly powerful is their deep integration with the content layer. Using special &lt;a href="https://www.sanity.io/docs/specifications/groq-functions#a64594a50318" rel="noopener noreferrer"&gt;&lt;strong&gt;GROQ Delta Functions&lt;/strong&gt;&lt;/a&gt;, your code can understand not just the current state of a document, but precisely &lt;strong&gt;what changed&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;before()&lt;/code&gt; and &lt;code&gt;after()&lt;/code&gt; give you snapshots of the document before and after the triggering event&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;delta::changedAny()&lt;/code&gt; and &lt;code&gt;delta::changedOnly()&lt;/code&gt; let you check if specific fields were modified. Did the title change? Or &lt;em&gt;only&lt;/em&gt; the title?&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;delta::operation()&lt;/code&gt; tells you if the document was created, updated, or deleted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can build workflows that only run when a specific field is changed or when a document is first created, preventing unnecessary executions and complex boilerplate code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure as Code with Blueprints
&lt;/h3&gt;

&lt;p&gt;A powerful engine needs a robust control system. &lt;strong&gt;Blueprints&lt;/strong&gt; provide exactly that. They bring the discipline of infrastructure-as-code to your Sanity project, allowing you to define and manage your Functions (and other future Sanity resources) in a version-controlled file: &lt;code&gt;sanity.blueprint.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The workflow is clean and mirrors best practices from modern DevOps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define&lt;/strong&gt;: you declare your functions and their triggers in the blueprint file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan&lt;/strong&gt;: run ⁠&lt;code&gt;sanity blueprints plan&lt;/code&gt; to see what changes will be made to your cloud environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy&lt;/strong&gt;: execute ⁠&lt;code&gt;sanity blueprints deploy&lt;/code&gt; to push your functions to Sanity's infrastructure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manage&lt;/strong&gt;: you can view info with &lt;code&gt;sanity blueprints info&lt;/code&gt; or tear down resources with &lt;code&gt;⁠sanity blueprints destroy&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach makes your automation setup repeatable, reviewable, and easy to manage as a team. And for a quick start, Sanity has provided a library of &lt;a href="https://www.sanity.io/exchange/type=recipes/by=sanity" rel="noopener noreferrer"&gt;Recipes&lt;/a&gt; with pre-built patterns for common use cases.&lt;/p&gt;

&lt;p&gt;Now we have the full picture: the AI brains with Agent Actions and the automation engine with Functions, all managed via Blueprints. Now, let’s put it all together and build something real.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Theory to Practice
&lt;/h2&gt;

&lt;p&gt;This is where the new toolkit moves from a list of features to a powerful, integrated system. At FocusReactive, we immediately used these tools to tackle a common content challenge: generating relevant, high-quality FAQ sections for our technical blog posts.&lt;/p&gt;

&lt;p&gt;Here’s how we built it, showcasing how you can use Agent Actions both manually with a UI trigger and automatically in a hands-off workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  FAQ Schema
&lt;/h3&gt;

&lt;p&gt;First things first, we need a home for our FAQ content. We'll set up a pretty standard schema with types for the FAQ section and its individual items:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// schemas/blog/postFaq.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postFaq&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Post FAQ&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Rule&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;Rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FAQ Items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postFaqItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
      &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Rule&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;Rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&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="p"&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;// schemas/blog/postFaqItem.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;defaul&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postFaqItem&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Post FAQ Item&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="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Rule&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;Rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;richText&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
      &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Rule&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;Rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom Studio Action
&lt;/h3&gt;

&lt;p&gt;First, we wanted to give editors manual control. What if they want to regenerate an FAQ for an already-published post? This is a perfect use case for calling an Agent Action directly from a custom &lt;strong&gt;Document Action&lt;/strong&gt; in the Studio.&lt;/p&gt;

&lt;p&gt;This demonstrates the power of the Agent Action API on its own - no serverless function needed.&lt;/p&gt;

&lt;p&gt;We created a custom action that appears in the document's dropdown menu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// actions/GenerateFaqAction.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;DocumentActionComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;DocumentActionDescription&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;DocumentActionProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;useClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sanity&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RobotIcon&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sanity/icons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GenerateFaqAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DocumentActionComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DocumentActionProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;DocumentActionDescription&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isGenerating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsGenerating&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agentClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleGenerateFaq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setIsGenerating&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="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;published&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;alert&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 document data available&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;_id&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;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&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="s2"&gt;`🔄 Regenerating FAQ for: &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;span class="s2"&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;agentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;unset&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;faq&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;commit&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="s2"&gt;`🗑️ Existing FAQ cleared for: &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;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;agentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;schemaId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_.schemas.default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;targetDocument&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;edit&lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;},&lt;/span&gt;
                &lt;span class="c1"&gt;// The instruction below is a simplified example. In a real-world application,&lt;/span&gt;
                &lt;span class="c1"&gt;// you could provide much more detailed requirements, including rules for&lt;/span&gt;
                &lt;span class="c1"&gt;// tone of voice, brand guidelines, or specific formatting for the output&lt;/span&gt;
                &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Generate 5-7 relevant FAQ items for this blog post about $blogTitle.
Create questions that readers would commonly ask about this technical topic.
Provide comprehensive, helpful answers based on the blog content ($blogContent) and description ($blogDescription).
Make the questions specific and actionable.
Focus on practical implementation details, common issues, and best practices.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;instructionParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;blogTitle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="na"&gt;blogContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="na"&gt;blogDescription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;faq&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="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="s2"&gt;`✅ FAQ regenerated successfully for: &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;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onComplete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`✅ FAQ generated successfully for "&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;span class="s2"&gt;"!&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;n&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;nThe document has been updated.`&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;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;❌ Error generating FAQ:&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`❌ Error generating FAQ: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unknown error&lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setIsGenerating&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isGenerating&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generating FAQ...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generate FAQ&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RobotIcon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isGenerating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;onHandle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;handleGenerateFaq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generate FAQ section using AI based on the blog content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this in place, an editor can now click a button in the Studio, and the AI will generate and populate the FAQ field on demand.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Triggering on Publish
&lt;/h3&gt;

&lt;p&gt;Now for the magic. We want to generate the FAQ automatically when a new post is published. This is where Functions and Blueprints come into play.&lt;/p&gt;

&lt;p&gt;We first define our workflow in &lt;code&gt;sanity.blueprint.ts&lt;/code&gt;. We're telling Sanity to run a function named &lt;code&gt;generate-faq&lt;/code&gt; only on the publish event, and only for documents that are posts and don't already have an FAQ.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// sanity.blueprint.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineBlueprint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defineDocumentFunction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sanity/blueprints&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineBlueprint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nf"&gt;defineDocumentFunction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;generate-faq&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;publish&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_type == "post" &amp;amp;&amp;amp; !defined(faq)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;projection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{_id, title}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create the function itself. This code will look very similar to our custom action, but instead of being triggered by a user click, it's triggered by the publish event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// functions/generate-faq/index.ts &lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;documentEventHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sanity/functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sanity/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;documentEventHandler&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;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="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;clientOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Required for Agent Actions&lt;/span&gt;
        &lt;span class="na"&gt;useCdn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="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="s2"&gt;`🚀 FAQ generation triggered for: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;❌ Missing _id in event data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="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="s2"&gt;`🤖 Generating FAQ using AI for: &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;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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;schemaId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_.schemas.fr-website&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;targetDocument&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;edit&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`drafts.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Create/update draft version instead of published&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Generate 5-7 relevant FAQ items for this blog post about $blogTitle.
Create questions that readers would commonly ask about this technical topic.
Provide comprehensive, helpful answers based on the blog content ($blogContent) and description ($blogDescription).
Make the questions specific and actionable.
Focus on practical implementation details, common issues, and best practices.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;instructionParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;blogTitle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;blogContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;blogDescription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;faq&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;noWrite&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;local&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Don't write when testing locally&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="s2"&gt;`✅ Successfully generated FAQ for: &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;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="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;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="s2"&gt;`❌ Error generating FAQ for &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;span class="s2"&gt;:`&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="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy and Go
&lt;/h3&gt;

&lt;p&gt;Finally, we deploy our automation with a single command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sanity blueprints deploy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And now our workflow is complete. We have an on-demand, manual trigger inside the Studio and a fully automated, hands-off process for new content. This dual approach perfectly illustrates the flexibility of Sanity's new toolkit - you can meet editors where they are, while also building powerful, invisible automations.&lt;/p&gt;

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

&lt;p&gt;The June 2025 update is more than just another set of features, it represents a fundamental shift in what we can expect from a content platform. At FocusReactive, we couldn't be more excited about this evolution.&lt;/p&gt;

&lt;p&gt;We are already putting this knowledge into practice and are committed to using these capabilities to empower our clients. Our goal is to equip their content managers with the best possible tools, creating intuitive, AI-assisted workflows that automate repetitive tasks and unlock new creative potential.&lt;/p&gt;

&lt;p&gt;A huge thank you to the entire Sanity team for their incredible vision and execution. It feels like every month they deliver something new and exciting that moves the entire industry forward. We can't wait to build with this and see what comes next.&lt;/p&gt;

&lt;p&gt;To give you a concrete example of the output, you can see the AI-generated FAQ section for this article right below.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>news</category>
    </item>
    <item>
      <title>How to Optimize Vercel Costs</title>
      <dc:creator>Alex Hramovich</dc:creator>
      <pubDate>Tue, 26 Nov 2024 09:11:16 +0000</pubDate>
      <link>https://dev.to/focusreactive/how-to-optimize-vercel-costs-bd</link>
      <guid>https://dev.to/focusreactive/how-to-optimize-vercel-costs-bd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;👉 Read the full article &lt;a href="https://focusreactive.com/vercel-cost-optimization/?source=devto" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vercel is a go to hosting platform for Next.js projects. But let’s face it — &lt;strong&gt;hosting costs can add up quickly&lt;/strong&gt;. Whether you're on the PRO plan or considering the Enterprise tier, it's essential to ensure you're not overpaying for features you don’t need.&lt;/p&gt;

&lt;h2&gt;
  
  
  PRO vs Enterprise: The Smarter Choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PRO&lt;/strong&gt; Plan ($20/user/month): Offers generous resources like 1TB of bandwidth and full access to Edge Middleware. For most teams, this plan is enough, and additional bandwidth or serverless execution time can be purchased without committing to the Enterprise tier. Scaling this way often costs significantly less than jumping to Enterprise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise&lt;/strong&gt; Plan ($3,500+/month): Tailored for large-scale organizations requiring features like SSO, static IPs, and SLAs. However, many teams can replicate similar benefits by optimizing their PRO plan setup and buying extra resources when needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Why PRO with Add-Ons Makes Sense ?
&lt;/h5&gt;

&lt;p&gt;Instead of an enterprise monthly commitment, purchasing additional resources under the PRO plan keeps costs predictable and aligned with your actual usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Consider Self-Hosting
&lt;/h2&gt;

&lt;p&gt;If you’ve outgrown the PRO plan but the Enterprise plan feels like overkill, self-hosting can be a strong alternative:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cost Efficiency: Host for $500–$1,000/month with platforms like Cloudflare or Render, gaining flexibility and control over your infrastructure.&lt;/li&gt;
&lt;li&gt;Improved Performance: Eliminate serverless bottlenecks with dedicated servers tailored for dynamic applications.&lt;/li&gt;
&lt;li&gt;Custom Caching Strategies: Optimize your setup beyond what’s possible with Vercel alone.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;For most teams, the PRO plan with add-ons is the most cost-effective solution. It provides scalability and control without the significant expense of Enterprise. For advanced needs, self-hosting can offer a tailored and budget-friendly alternative.&lt;/p&gt;

</description>
      <category>vercel</category>
      <category>nextjs</category>
      <category>hosting</category>
    </item>
    <item>
      <title>Next.JS CMS — Top choices in 2024</title>
      <dc:creator>Aleksei Zhilyuk</dc:creator>
      <pubDate>Thu, 31 Oct 2024 09:38:54 +0000</pubDate>
      <link>https://dev.to/focusreactive/nextjs-cms-top-choices-in-2024-o38</link>
      <guid>https://dev.to/focusreactive/nextjs-cms-top-choices-in-2024-o38</guid>
      <description>&lt;h2&gt;
  
  
  WHY A HEADLESS CMS FOR YOUR NEXT.JS PROJECT?
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://focusreactive.com/headless-cms-expert-agency/" rel="noopener noreferrer"&gt;headless CMS&lt;/a&gt; serves as a backend-only content repository that provides content via an API, making it displayable on any device. This approach separates content management from its presentation, which is particularly advantageous for &lt;a href="https://focusreactive.com/next-js-expert-agency/" rel="noopener noreferrer"&gt;NextJS projects&lt;/a&gt;. By using a headless CMS, developers can fully leverage Next.js features like &lt;a href="https://nextjs.org/docs/pages/building-your-application/rendering/server-side-rendering" rel="noopener noreferrer"&gt;server-side rendering&lt;/a&gt; and &lt;a href="https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation" rel="noopener noreferrer"&gt;static site generation&lt;/a&gt;, optimizing both SEO and performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  ADVANTAGES OF INTEGRATING A HEADLESS CMS WITH NEXTJS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://focusreactive.com/next-js-expert-agency/" rel="noopener noreferrer"&gt;NextJS&lt;/a&gt; is a powerful framework for building efficient and scalable web applications. &lt;/p&gt;

&lt;h3&gt;
  
  
  Here are specific advantages of integrating a headless CMS with Next.js:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enhanced Performance&lt;/strong&gt;: Next.js excels in fast page loads through features like incremental static regeneration and server-side rendering. A headless CMS complements this by efficiently delivering content through APIs, reducing load times and server strain. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved SEO:&lt;/strong&gt; Next.js facilitates SEO-friendly site structures, which can be enhanced with a headless CMS that supports SEO optimization through metadata management and structured content delivery.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; As your project grows, the need to handle more traffic and content efficiently becomes crucial. A headless CMS can scale independently from the front-end, making it easier to manage large volumes of data without impacting the front-end performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexibility in Development:&lt;/strong&gt; Developers can use their preferred front-end technologies and frameworks without constraints imposed by traditional CMS platforms. This means you can use the latest Next.js features and updates as soon as they are released.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Better Security and Stability:&lt;/strong&gt; By decoupling the CMS from the presentation layer, security is enhanced as potential vulnerabilities in the CMS do not directly expose the front-end to security risks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Streamlined Workflows:&lt;/strong&gt; A headless CMS can support multiple front-ends simultaneously, which is advantageous for projects aiming to deliver content across different platforms and devices.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These benefits make a headless CMS an excellent match for Next.js, ensuring developers can build modern, secure, and high-performing applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://focusreactive.com/contentful-expert-agency/" rel="noopener noreferrer"&gt;Contentful&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/contentful-cms-overview/" rel="noopener noreferrer"&gt;Contentful&lt;/a&gt; is a leader in the headless CMS market, offering a comprehensive suite of features that cater to developers and content creators alike.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Integration:&lt;/strong&gt; 
With its React SDK, integrating Contentful with Next.js projects is a breeze, providing a seamless workflow for developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility:&lt;/strong&gt; 
Contentful's content modeling capabilities are unmatched, allowing for the creation of complex content structures tailored to any project's needs. Its environment feature supports staging and production setups, enabling a robust development workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; 
Its Delivery API is built for speed, ensuring that content loads quickly, which is crucial for maintaining high performance in Next.js applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community and Support:&lt;/strong&gt; 
A vast community and extensive documentation mean that developers can easily find solutions or get help when needed. Contentful also offers professional support services for enterprise users, ensuring that any issues can be swiftly addressed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.contentful.com/pricing/?tab=platform" rel="noopener noreferrer"&gt;Contentful pricing&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basic:&lt;/strong&gt; $300/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Premium:&lt;/strong&gt; Custom pricing&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://focusreactive.com/storyblok-expert-agency/" rel="noopener noreferrer"&gt;Storyblok&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/storyblok-cms-overview/" rel="noopener noreferrer"&gt;Storyblok&lt;/a&gt; stands out for its visual editor and block-based approach to content management, making it particularly friendly for both developers and content creators.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Integration:&lt;/strong&gt; 
Storyblok's component-based approach integrates seamlessly with Next.js, allowing developers to map components in Storyblok to React components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility:&lt;/strong&gt; 
The platform offers incredible flexibility through its block-based content system, enabling creators to build dynamic, rich content experiences without needing developer intervention for layout changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; 
Storyblok's content delivery is optimized for speed, utilizing a CDN to ensure content is served quickly to Next.js applications globally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community and Support:&lt;/strong&gt; 
Storyblok has a rapidly growing community and provides extensive documentation, tutorials, and customer support, making it easy for developers to get started and find help when needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.storyblok.com/pricing" rel="noopener noreferrer"&gt;Storyblok pricing&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Community Plan:&lt;/strong&gt; Free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entry Plan:&lt;/strong&gt; €99/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise:&lt;/strong&gt; €3299/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise Plus:&lt;/strong&gt; Custom pricing&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://focusreactive.com/sanity-expert-agency/" rel="noopener noreferrer"&gt;Sanity.io&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/sanity-cms-overview/" rel="noopener noreferrer"&gt;Sanity.io&lt;/a&gt; differentiates itself with its real-time content editing experience and a highly customizable content studio.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Integration:&lt;/strong&gt; The platform offers excellent support for React and Next.js, including real-time preview capabilities that are invaluable during development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility:&lt;/strong&gt; The customizable content studio and the innovative portable text feature provide developers and content editors with the power to embed rich content structures directly within textual content, making it highly versatile.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; Sanity.io leverages GROQ and GraphQL for data querying, offering efficient and flexible options for fetching data, which enhances app performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community and Support:&lt;/strong&gt; With a vibrant community and plenty of guides, finding help or inspiration is easy. Sanity.io also hosts regular developer streams and community events, fostering a strong sense of community.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.sanity.io/pricing" rel="noopener noreferrer"&gt;Sanity pricing&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Growth:&lt;/strong&gt; $15/month per user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise:&lt;/strong&gt; Custom pricing&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://focusreactive.com/directus-expert-agency/" rel="noopener noreferrer"&gt;Directus&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/directus-cms-overview/" rel="noopener noreferrer"&gt;Directus&lt;/a&gt; is an open-source option that stands out for its API-driven approach and extensive customization capabilities.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Integration:&lt;/strong&gt; 
Offering both RESTful API and GraphQL endpoint, Directus provides versatile integration options with Next.js, catering to different developer preferences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility:&lt;/strong&gt; 
Being open-source, Directus allows for deep customization, from the admin UI to the underlying database schema. This flexibility ensures that developers can tailor the CMS to fit the project's exact requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; 
While performance is generally excellent, it can vary depending on how the Directus backend is configured. However, the ability to directly query the database ensures minimal overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community and Support:&lt;/strong&gt; 
The growing open-source community around Directus is a rich resource for troubleshooting and inspiration. Directus also offers dedicated support plans for businesses requiring more personalized assistance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://directus.io/pricing" rel="noopener noreferrer"&gt;Directus pricing&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosted:&lt;/strong&gt; License required &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professional Cloud:&lt;/strong&gt; $99/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise Cloud:&lt;/strong&gt; Custom&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://payloadcms.com/" rel="noopener noreferrer"&gt;Payload CMS&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/payload-cms-overview" rel="noopener noreferrer"&gt;Payload CMS&lt;/a&gt; is a newer entrant in the headless CMS space but has quickly gained attention for its developer-focused features and flexibility.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Integration:&lt;/strong&gt; 
Designed with developers in mind, Payload CMS offers full TypeScript support and a highly customizable admin UI, making it a perfect match for Next.js applications that utilize TypeScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility:&lt;/strong&gt; 
It stands out for its deep customization capabilities, allowing full control over the admin UI and the APIs. This level of customization makes it possible to tailor every aspect of the CMS to the project's needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; 
Payload CMS is optimized for performance, featuring efficient data handling and delivery mechanisms. This focus on performance is evident in the speed and responsiveness of Next.js applications powered by Payload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community and Support:&lt;/strong&gt; 
Although the community is currently smaller, it's rapidly growing. The developers are actively involved in expanding the documentation and offering support, ensuring users have the resources they need.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://payloadcms.com/cloud-pricing" rel="noopener noreferrer"&gt;Payload CMS pricing&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standard:&lt;/strong&gt; $35/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro:&lt;/strong&gt; $199/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise:&lt;/strong&gt; Custom&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://prismic.io/" rel="noopener noreferrer"&gt;Prismic&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/prismic-cms-overview" rel="noopener noreferrer"&gt;Prismic&lt;/a&gt; offers a straightforward and developer-friendly approach to content management, making it a popular choice for many Next.js projects.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Integration:&lt;/strong&gt; Its REST API and support for webhooks make integrating Prismic with Next.js straightforward, facilitating both static site generation and server-side rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility:&lt;/strong&gt; The slices feature allows for building dynamic page layouts with ease, offering developers and content creators a flexible and powerful tool for designing content-rich pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; Prismic's use of a CDN for content delivery ensures fast load times, a critical factor for maintaining high performance in web applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community and Support:&lt;/strong&gt; While Prismic has good documentation and support, its community may not be as large as some others, but the quality of support and resources is high.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://prismic.io/pricing" rel="noopener noreferrer"&gt;Prismic pricing&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free:&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starter:&lt;/strong&gt; $10/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small:&lt;/strong&gt; $25/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Medium:&lt;/strong&gt; $150/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platinum:&lt;/strong&gt; $675/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise:&lt;/strong&gt; Custom&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://focusreactive.com/ghost-cms-overview/" rel="noopener noreferrer"&gt;Ghost CMS&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/ghost-cms-overview/" rel="noopener noreferrer"&gt;Ghost CMS&lt;/a&gt; is an open-source platform focused on blogging and online publishing. Built on Node.js, it is renowned for its simplicity and speed, providing a seamless content creation process. Ghost is ideal for bloggers and organizations seeking a lightweight CMS that enhances SEO and content delivery.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SEO Optimization&lt;/strong&gt;: Provides SEO-friendly features like automatic sitemap generation and rich meta tagging, complementing Next.js's SEO capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern Technology Stack&lt;/strong&gt;: Built on a Node.js stack, Ghost aligns well with the server-side rendering features of Next.js.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight and Fast&lt;/strong&gt;: Its lightweight nature enhances the performance benefits of Next.js, making it ideal for projects requiring high-speed content delivery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Membership and Subscriptions&lt;/strong&gt;: Native support for memberships and subscriptions, enabling monetization in Next.js applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://ghost.org/pricing/" rel="noopener noreferrer"&gt;Ghost CMS pricing&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Starter:&lt;/strong&gt; from $10/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creator:&lt;/strong&gt; $25/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team:&lt;/strong&gt; $50/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business:&lt;/strong&gt; $199/month&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://focusreactive.com/kentiko-kontent-overview/" rel="noopener noreferrer"&gt;Kentico Kontent&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/kentiko-kontent-overview/" rel="noopener noreferrer"&gt;Kontent.ai&lt;/a&gt;, formerly known as Kentico Kontent, is a cloud-based CMS designed for content collaboration and delivery across multiple channels. It supports robust content modeling and real-time collaboration, making it suitable for large enterprises and digital agencies managing diverse content ecosystems.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workflow Management&lt;/strong&gt;: Offers robust tools for collaborative content creation and workflow management, supporting the development cycles typical in Next.js projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content Modeling&lt;/strong&gt;: Features powerful content modeling tools to structure content efficiently, which is key when building scalable Next.js applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Capabilities&lt;/strong&gt;: Comprehensive APIs facilitate efficient data exchanges, crucial for integrating with Next.js's data fetching methods like &lt;code&gt;getStaticProps&lt;/code&gt; and &lt;code&gt;getServerSideProps&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-channel Delivery&lt;/strong&gt;: Ensures consistent content delivery across all platforms, which pairs well with Next.js's universal rendering capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://focusreactive.com/hygraph-cms-overview/" rel="noopener noreferrer"&gt;Hygraph&lt;/a&gt; (formerly GraphCMS)
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/hygraph-cms-overview/" rel="noopener noreferrer"&gt;Hygraph&lt;/a&gt; is a headless CMS that uses GraphQL to enhance content management and delivery. It allows for the quick development of content APIs with minimal coding, ideal for projects requiring complex content structures and relationships.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GraphQL Native&lt;/strong&gt;: Being a GraphQL-native CMS, Hygraph provides powerful developer tools that perfectly match Next.js's data fetching strategies, enhancing the development of complex applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema Management&lt;/strong&gt;: Easy management of content schemas with an intuitive interface complements Next.js's dynamic routing and static generation features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Collaboration&lt;/strong&gt;: Supports real-time collaboration and version control, which are beneficial for teams working on Next.js applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich Media Management&lt;/strong&gt;: Advanced media handling capabilities ensure that multimedia content is optimized for performance in Next.js applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://hygraph.com/pricing" rel="noopener noreferrer"&gt;Hygraph pricing&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free forever:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professional:&lt;/strong&gt; $199/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale:&lt;/strong&gt; $799/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom:&lt;/strong&gt; Contact to get a quote&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://focusreactive.com/butter-cms-overview/" rel="noopener noreferrer"&gt;ButterCMS&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/butter-cms-overview/" rel="noopener noreferrer"&gt;ButterCMS&lt;/a&gt; is a straightforward headless CMS that integrates easily with existing projects thanks to its comprehensive API and SDKs. Known for its ease of use, Butter CMS is favored by marketers and developers needing to deploy content-rich sites quickly.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Marketing Integration&lt;/strong&gt;: Offers robust tools for SEO and content marketing, enhancing the marketing aspects of Next.js websites.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple API&lt;/strong&gt;: Its simple RESTful API is easy to integrate with Next.js, supporting quick implementation in existing projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SDKs and Libraries&lt;/strong&gt;: Provides SDKs for various programming languages, making it easy to integrate with Next.js and other parts of your technology stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalization Features&lt;/strong&gt;: Content personalization capabilities align well with the dynamic and static rendering options of Next.js.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://buttercms.com/pricing/" rel="noopener noreferrer"&gt;Butter CMS pricing&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Micror:&lt;/strong&gt; $99/month &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Startup:&lt;/strong&gt; $199/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small Business:&lt;/strong&gt; $375/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise + Agency:&lt;/strong&gt; Custom&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://focusreactive.com/strapi-cms-overview/" rel="noopener noreferrer"&gt;Strapi&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://focusreactive.com/strapi-cms-overview/" rel="noopener noreferrer"&gt;Strapi&lt;/a&gt; is an open-source, customizable headless CMS that supports various databases and frontend frameworks. Its API-centric approach and community-driven development make it a flexible choice for building scalable web applications. Strapi appeals to developers looking for control over their CMS environment.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open Source&lt;/strong&gt;: One of the few fully open-source options available, giving developers complete control over their CMS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosting Capability&lt;/strong&gt;: Can be self-hosted, providing full control over the hosting environment and security aspects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizable UI&lt;/strong&gt;: Offers a customizable admin panel built with React, making it a natural choice for React developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community and Plugins&lt;/strong&gt;: A vibrant community and a wide range of plugins available for extended functionalities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://strapi.io/pricing" rel="noopener noreferrer"&gt;Strapi pricing&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Community:&lt;/strong&gt; Free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer:&lt;/strong&gt; $29/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro:&lt;/strong&gt; $99/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team:&lt;/strong&gt; $499/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise:&lt;/strong&gt; Custom&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Conclusion and Recommendations
&lt;/h2&gt;

&lt;p&gt;After a detailed analysis of each platform, our top recommendations for Next.js developers based on specific project needs and priorities are:&lt;/p&gt;

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

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://focusreactive.com/sanity-cms-overview/" rel="noopener noreferrer"&gt;Sanity.io&lt;/a&gt;&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;Perfect for projects that require real-time content updates and a high degree of customization in the content editing experience.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://focusreactive.com/storyblok-cms-overview/" rel="noopener noreferrer"&gt;Storyblok&lt;/a&gt;&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;Ideal for those who value intuitive content management with a visual editor and a block-based approach, offering ease of use for developers and content creators alike.&lt;/p&gt;

&lt;p&gt;If you are considering a &lt;a href="https://focusreactive.com/migration-from-wordpress-to-headless-cms/" rel="noopener noreferrer"&gt;migration to Headless CMS&lt;/a&gt; or you are building it from scratch - &lt;a href="https://focusreactive.com/#mail-us" rel="noopener noreferrer"&gt;contact us&lt;/a&gt;, we are &lt;a href="https://focusreactive.com/headless-cms-expert-agency/" rel="noopener noreferrer"&gt;headless cms agency&lt;/a&gt; and we can set up a free consultation around the project you have in mind &lt;/p&gt;

</description>
      <category>headlesscms</category>
      <category>nextjs</category>
      <category>jamstack</category>
    </item>
    <item>
      <title>Next.js Conf 2024 Highlights and React Framework Future</title>
      <dc:creator>Aleksei Zhilyuk</dc:creator>
      <pubDate>Thu, 31 Oct 2024 09:26:32 +0000</pubDate>
      <link>https://dev.to/focusreactive/nextjs-conf-2024-highlights-and-react-framework-future-1bdb</link>
      <guid>https://dev.to/focusreactive/nextjs-conf-2024-highlights-and-react-framework-future-1bdb</guid>
      <description>&lt;p&gt;While the overall ambitious tone of the previous conference editions have cooled off, we enthusiastically welcomed the direction the presenting team have taken, focusing on making Next.js API more streamlined, and self-hosting friendly. We saw updates and celebrated stable release of Turbopack for Dev, and insightful deep-dives from people behind the framework. &lt;/p&gt;

&lt;p&gt;Followed up by case studies of major Next.js adopters, and strategic partners, including, our most technological Headless CMS of choice - &lt;a href="https://focusreactive.com/sanity-expert-agency/" rel="noopener noreferrer"&gt;Sanity&lt;/a&gt;, which went all in with their Next.js 15 support and innovative “live” CMS content approach. We got so excited about the last one that we even wrote a separate blog post breaking down the vision behind the new architecture of choice when it comes to Next.js+Sanity combo.&lt;/p&gt;

&lt;p&gt;Let’s break down some of the talks we followed the most:&lt;/p&gt;

&lt;h2&gt;
  
  
  Opening Keynote
&lt;/h2&gt;

&lt;p&gt;Guillermo Rauch (CEO, Vercel &amp;amp; Creator of Next.js) welcomes everyone to the fifth anniversary of Next.js and begins his speech by expressing gratitude to the main contributors to Next.js.&lt;/p&gt;

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

&lt;p&gt;A lot happened during the year:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4000 PRs&lt;/li&gt;
&lt;li&gt;5 Next.js releases were made&lt;/li&gt;
&lt;li&gt;570 new contributors joined the project&lt;/li&gt;
&lt;li&gt;Next.js reaches 7 million downloads on NPM&lt;/li&gt;
&lt;li&gt;Many large companies have already migrated to APP Router, such as PayPal, wayfair, xAI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Guillermo Rauch believes that Next.js and its ecosystem is something we can rely on in the future. Next.js is used all over the world to create everything from the simplest websites to complex, sophisticated applications.&lt;/p&gt;

&lt;p&gt;Guillermo Rauch was guided by these principles when creating Next.js&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make it work &lt;/li&gt;
&lt;li&gt;Make it right&lt;/li&gt;
&lt;li&gt;Make it fast&lt;/li&gt;
&lt;li&gt;Make it blazing fast&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;APP Router was created to make data fetching and rendering more predictable, since according to Guillermo Rauch, developers should not worry about caching and focus on creating the application.&lt;/p&gt;

&lt;p&gt;In order for the idea to turn into a product as quickly as possible and the time for each iteration to be as short as possible Guillermo Rauch is pleased to announce that Turbopack is finally stable. &lt;/p&gt;

&lt;p&gt;The new compiler is 50% faster than the previous one for initial compilation and 90% faster for Fast Refresh.&lt;/p&gt;

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

&lt;p&gt;Coming soon for Turbopack: Turbopack uses persistent cache for its fast performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplifying Next.js Cache API
&lt;/h3&gt;

&lt;p&gt;Next, Delba de Oliveira (DX Engineer at Vercel) shows how to make the demo application faster using caching and introduces a new experimental NextJS “use cache” directive that allows you to explicitly specify that a component or the result of a function execution should be cached. &lt;/p&gt;

&lt;p&gt;This directive works both in components, similar to “use client”, and in functions, similar to “use server”, as well as a new API “cacheTag” for cache keys and “cacheLife” for specifying how long a given cache should live.&lt;/p&gt;

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

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

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

&lt;p&gt;Developers can try these experimental changes in the canary version of Next.js. We will also soon write up our own deep-dive into the new “use cache” API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better self-hosting of Next.js
&lt;/h3&gt;

&lt;p&gt;Next, Lee Robinson (VP of Product at Vercel) appears on stage to uncover improvements for &lt;a href="https://focusreactive.com/self-hosted-next-js-when-vercel-is-not-an-option/" rel="noopener noreferrer"&gt;self-hosted Next.js&lt;/a&gt; they have shipped, re-iterating Vercel’s focus on keeping Next.js open-source first.&lt;/p&gt;

&lt;p&gt;In v15, the Vercel team has made it easier to configure how caching works by default, also simplifying the required minimal DevOps setup for self hosting Next.js. Documentation covering various deployment scenarios and templates have also been greatly improved, including the &lt;a href="https://github.com/nextjs" rel="noopener noreferrer"&gt;launch of Next.js community GitHub org&lt;/a&gt; with up-to-date redeployment recipes for community’s most popular hosting targets.&lt;/p&gt;

&lt;p&gt;Previously, Next.js used a web assembly-based image optimization library, but they were dissatisfied with the fact that this library consumed a lot of memory, so now it uses “Sharp”, which is installed automatically.&lt;/p&gt;

&lt;p&gt;Default cache control headers have been updated&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zy5l6weifdwf75crw7m.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zy5l6weifdwf75crw7m.webp" alt="next14 vs next15 cache control headers" width="800" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;h3&gt;
  
  
  AMA: Next.js Team
&lt;/h3&gt;

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

&lt;p&gt;Variety of topics have been covered during the Ask Me Anything session with the Next.js team, we suggest you dive into it yourself on the &lt;a href="https://www.youtube.com/live/WLHHzsqGSVQ?si=rV4XvraDRztZINiB&amp;amp;t=4915" rel="noopener noreferrer"&gt;stream recording&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Server Components: Elevating speed, interactivity, and user experience
&lt;/h2&gt;

&lt;p&gt;Aurora starts her talk by saying that the RSC have changed the way we build apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some of the new possibilities, that come with the RSC:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch data async inside the component itself&lt;/li&gt;
&lt;li&gt;Access backend resources directly from component&lt;/li&gt;
&lt;li&gt;No JS is ship to the client&lt;/li&gt;
&lt;li&gt;Streaming&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;RSC and latest next.js features help increase speed of not only websites, but also development velocity. New versions of next.js and react help you split compute load between client and a server, which will help you build an application based on your needs. Another important aspects that have beed improved, are interactivity and ability to easily build responsive apps.&lt;/p&gt;

&lt;p&gt;With the new features comes new limitations, for example you can’t access client hooks such as useState, useEffect, or browser information in such components.&lt;/p&gt;

&lt;p&gt;New development patterns to leverage the latest features and create a stunning UI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Move data fetching closer to UI&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Instead of fetching data on top level, and make requests blocking render, move data fetching inside the component, and wrap component in Suspence boundary.&lt;/p&gt;

&lt;p&gt;Before and after&lt;/p&gt;

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

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

&lt;ol&gt;
&lt;li&gt;Add client component and preserve request non-blocking fashion&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you need to make a component inside Suspence boundary client-side, you will be forced to remove server function call from it. In this case, create a promise on the top level, pass it to client component as a prop, and resolve using react new use() function. It will help you avoid render blocking and keep client component in suspense boundary, to show a static shell on initial render.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0o8rs6aij5m6tebi7jo.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0o8rs6aij5m6tebi7jo.webp" alt="passing promise from RSC to RCC" width="535" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;useTransition, useOptimistic&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These new react hooks allows you to create a smooth transitions on any user’s action. Moreover, using these hooks you are able to show instant feedback to the user and mnot depend on network connection.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React cache&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use new cache function to prevent firing the same request multiple times. This means we can reuse existing pattern of calling data directly inside component and maintain composition.&lt;/p&gt;

&lt;p&gt;All these new features and patters allow us build fully interactive apps without use of useState and useEffect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best development practices:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resolve promises deep in the tree&lt;/li&gt;
&lt;li&gt;Display pending indicators&lt;/li&gt;
&lt;li&gt;Put state in the URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;New tools:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Leverage react 19 features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cache() - perform per-render caching for expensive func calls&lt;/li&gt;
&lt;li&gt;useOptimistic() - respond to user interactions instantly even when the request is slow&lt;/li&gt;
&lt;li&gt;use() - suspend client components as they resolve a promise passed down&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next.js features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;staleTimes - set state times for dynamic page segments to reuse them across subsequent requests&lt;/li&gt;
&lt;li&gt;PPR - statically renders parts of the page or layout to improve performance&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The long and winding road: CSR to static export to SSG
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Building user interfaces in the age of AI
&lt;/h3&gt;

&lt;p&gt;Oleg starts of by defining what is great interface? Great interface is measured by the ability to help users accomplish their task as quickly and as effortlessly as possible.&lt;/p&gt;

&lt;p&gt;The most important things here are speed and reliability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Generative UI?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is an umbrella for any project leveraging LLMs, in order to enhance user interface. It is a spectrum. Each side of the spectrum has it’s own tradeoffs and requirements. But they are united by the crucial role of LLM.&lt;/p&gt;

&lt;p&gt;Both edges of the spectrum has it’s own requirements,  tradeoffs and performance characteristics.&lt;/p&gt;

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

&lt;p&gt;The slide represents the current state of LLM’s capabilities for generating UI.&lt;/p&gt;

&lt;p&gt;Generating HTML from text is a hard problem with following challenges:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Slow. takes up to 5-7s to generate a HTML page on perplexity &lt;/li&gt;
&lt;li&gt;No reliable way to deploy it&lt;/li&gt;
&lt;li&gt;Hard to sync with design system&lt;/li&gt;
&lt;li&gt;Token inefficiency&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Perplexity team is focused on text to object generations instead.&lt;/p&gt;

&lt;p&gt;One of the patterns guys in Perplexity use is define schemas for each presentational component and define props based on schema.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1wdhpskj0bmoxezt3vu.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1wdhpskj0bmoxezt3vu.webp" alt="schema for component props" width="723" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then use component’s schema as input for the model. This way you can create simple components with streaming functionality using LLMs.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use LLMs as APIs&lt;/li&gt;
&lt;li&gt;Faster and cheaper &lt;/li&gt;
&lt;li&gt;Fits well into existing flow&lt;/li&gt;
&lt;li&gt;Easy to integrate&lt;/li&gt;
&lt;li&gt;Structured output&lt;/li&gt;
&lt;li&gt;React friendly JSON data&lt;/li&gt;
&lt;li&gt;Guaranteed to be valid&lt;/li&gt;
&lt;li&gt;Schemas are useful without LLMs&lt;/li&gt;
&lt;li&gt;Streaming UX&lt;/li&gt;
&lt;li&gt;Address re-rendering issues&lt;/li&gt;
&lt;li&gt;Use OSS libs&lt;/li&gt;
&lt;li&gt;Implementation depends on your code&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Optimizing LCP: Partial Prerendering deep dive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Wyatt Johnson
&lt;/h3&gt;

&lt;p&gt;Wyatt Johnson, a software engineer at Vercel, provides a comprehensive overview of “Partial Prerendering”, an experimental feature aimed at optimizing the Largest Contentful Paint (LCP) by combining the best of static and dynamic rendering techniques. This method has been developed to tackle the limitations of traditional rendering methods, improving site performance and user experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbe1d97oqnrtq4b6o3b5i.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbe1d97oqnrtq4b6o3b5i.webp" alt="what are Core Web Vitals?" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wyatt begins by explaining the significance of Core Web Vitals, particularly focusing on LCP, which measures the render time of the largest image or text block visible within the viewport. He highlights the challenges faced with traditional rendering approaches where developers must choose between the speed of static rendering and the flexibility of dynamic rendering. Static rendering, while fast, cannot incorporate request data, leading to delays in rendering dynamic content. Conversely, dynamic rendering incorporates request data but often at the expense of speed due to server response times.&lt;/p&gt;

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

&lt;p&gt;The session delves into the mechanics of Partial Prerendering (PPR), which allows for a static shell of a page to be generated at build time and served from the edge. Simultaneously, it sends a request back to the origin to complete the dynamic rendering. This approach minimizes the time to first byte and ensures that the page loads quickly while still supporting dynamic capabilities.&lt;/p&gt;

&lt;p&gt;Wyatt demonstrates practical applications of PPR in an e-commerce setting, showing how PPR can streamline the rendering process, reduce latency, and improve the user experience by delivering a fast initial load with dynamic capabilities intact. He further explains the technical implementation of PPR, discussing how it leverages React’s capabilities to suspend and resume rendering as needed, based on the dynamic content requirements.&lt;/p&gt;

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

&lt;p&gt;To conclude, Wyatt emphasizes the future potential of PPR in Next.js and the ongoing efforts to integrate this feature across different hosting environments. He expresses enthusiasm for the capabilities of Next.js in bridging the gap between static speed and dynamic flexibility, ultimately providing developers with the tools to build faster and more responsive web applications.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  That's a Wrap
&lt;/h2&gt;

&lt;p&gt;Thank you for following our highlights from the Next.js Conference 2024, we enjoy sharing these with the community, as we eagerly follow all the developments in the Next.js space.&lt;/p&gt;

&lt;p&gt;Follow our blog for more Next.js content and practical use cases that we have solved building a variety of Next.js apps; as well as the practices we developed through our &lt;a href="https://focusreactive.com/nextjs-performance-audit/" rel="noopener noreferrer"&gt;Performance and SEO audits&lt;/a&gt; for our clients.&lt;/p&gt;

&lt;p&gt;We are excited about the direction Next.js team took, prioritizing API simplicity,increased transparency and support towards non-Vercel clients, which is dearly important for us. We support the renewed open source spirit and simplicity it brings for deployment of Next.js to own cloud environments.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Top React Conferences to Attend in 2024</title>
      <dc:creator>Aleksei Zhilyuk</dc:creator>
      <pubDate>Tue, 27 Aug 2024 10:31:42 +0000</pubDate>
      <link>https://dev.to/focusreactive/top-react-conferences-to-attend-in-2024-54n0</link>
      <guid>https://dev.to/focusreactive/top-react-conferences-to-attend-in-2024-54n0</guid>
      <description>&lt;p&gt;The React community continues to grow and evolve, making 2024 an exciting year for developers who want to connect, learn, and share their knowledge. Whether you're an experienced pro or just getting started, attending a React conference is an excellent way to stay up-to-date with the latest trends, tools, and best practices. Below, we've outlined some of the top React conferences coming up in 2024 that you won't want to miss.&lt;/p&gt;

&lt;p&gt;For a full list of events, check out the &lt;a href="https://gitnation.com/events/react-conferences" rel="noopener noreferrer"&gt;React events&lt;/a&gt; on GitNation.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  1. React Summit US
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date:&lt;/strong&gt; November 19 - 22, 2024&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; New York, USA&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://reactsummit.us/" rel="noopener noreferrer"&gt;React Summit US&lt;/a&gt; is one of the largest React gatherings worldwide, bringing together industry leaders to discuss the latest in React technology, state management, performance optimization, and more. Whether you're interested in deep technical dives or broader industry trends, you'll find sessions and workshops that fit your needs.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  2. React Day Berlin
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date:&lt;/strong&gt; December 13 - 16, 2024&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; Berlin, Germany&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Berlin, a vibrant tech hub, hosts &lt;a href="https://reactday.berlin/" rel="noopener noreferrer"&gt;React Day Berlin&lt;/a&gt;, a must-attend event for React developers in Europe. This conference offers a perfect blend of technical sessions, hands-on workshops, and networking opportunities. Expect to hear from top-notch speakers, including React core team members and contributors from the open-source community.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  3. React Advanced London
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date:&lt;/strong&gt; October 25 - 28, 2024&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; London, UK&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://reactadvanced.com/" rel="noopener noreferrer"&gt;React Advanced London&lt;/a&gt; is one of the most anticipated React events. Known for its diverse lineup of speakers and in-depth sessions, this conference covers everything from fundamental React concepts to advanced design patterns. It's a great opportunity to meet fellow developers and immerse yourself in the tech scene.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet the FocusReactive Team
&lt;/h2&gt;

&lt;p&gt;FocusReactive is a co-organizer of these conferences, and our team will be actively participating in all of them. We’d love to connect with you—whether to chat about the latest trends in React, explore potential collaborations, or just say hello. If you're attending any of these events, don't hesitate to reach out to us!&lt;/p&gt;

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

&lt;p&gt;With so many incredible events on the horizon, 2024 is set to be a fantastic year for the React community. Each of these conferences offers unique opportunities to learn, network, and grow as a developer. Be sure to grab your tickets and join the community at these exciting gatherings.&lt;/p&gt;

&lt;p&gt;For more details on these and other React conferences, check out the full &lt;a href="https://gitnation.com/events/react-conferences" rel="noopener noreferrer"&gt;React conferences list&lt;/a&gt; by GitNation.&lt;/p&gt;

</description>
      <category>react</category>
    </item>
    <item>
      <title>How to Manage Multiple Domains with a Headless CMS</title>
      <dc:creator>Anton Meleshkin</dc:creator>
      <pubDate>Mon, 26 Aug 2024 10:24:14 +0000</pubDate>
      <link>https://dev.to/focusreactive/how-to-manage-multiple-domains-with-a-headless-cms-4b28</link>
      <guid>https://dev.to/focusreactive/how-to-manage-multiple-domains-with-a-headless-cms-4b28</guid>
      <description>&lt;p&gt;Hello, fellow developers! Today, we’re diving into a common challenge: "&lt;strong&gt;How can I manage 2+ domains under one CMS space?&lt;/strong&gt;" Luckily, with modern technologies, this is easier than you might think.&lt;/p&gt;

&lt;p&gt;For this guide, we'll use &lt;a href="https://www.storyblok.com/" rel="noopener noreferrer"&gt;Storyblok&lt;/a&gt; as our headless CMS (hCMS) of choice due to its intuitive design and flexible features. However, if you’re using a different hCMS, you can still apply the core principles discussed here, as long as your CMS supports folder-based organization.&lt;/p&gt;

&lt;p&gt;What will you learn in this guide? Here's a sneak peek:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How to bake a multi-domain Storyblok space&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tasty spices, aka small but very useful features&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handling international filling&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Scenario: Managing Multiple Domains
&lt;/h2&gt;

&lt;p&gt;Let’s imagine you have three domains that need to be managed under one hCMS workspace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;domain-1.com&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;domain-2.com&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;domain-3.com&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Organizing Content by Domain
&lt;/h3&gt;

&lt;p&gt;Start by creating folders within your CMS for each domain and fill them with the respective content. In Storyblok, this might look something like this:&lt;/p&gt;

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

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

&lt;p&gt;With your content neatly organized, the necessary preparations on the CMS side is complete. Now, let’s dive into the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Configuring Data Fetching in Next.js
&lt;/h3&gt;

&lt;p&gt;In this guide, we'll use &lt;strong&gt;Next.js&lt;/strong&gt; along with &lt;strong&gt;Vercel&lt;/strong&gt; for deployment. The key here is to configure data fetching based on the domain, which will allow your application to serve the correct content dynamically.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example: Fetching Data for a Specific Domain
&lt;/h4&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;getData&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storyblokApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getStoryblokApi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&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;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;storyblokApi&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="s2"&gt;`cdn/stories/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_BASE_PATH&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="nx"&gt;slug&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="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;draft&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Fetches the draft version of the content&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="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;story&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;story&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;key&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;story&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;revalidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Revalidate every 24 hours&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/404&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Redirect to 404 page if content is not found&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;h4&gt;
  
  
  Environment Variable Setup
&lt;/h4&gt;

&lt;p&gt;To ensure your application knows which domain it’s serving, set up an environment variable in your &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_BASE_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Deploying on Vercel
&lt;/h3&gt;

&lt;p&gt;When deploying to Vercel, you’ll need to create a separate project for each domain. In each project, configure the environment variables accordingly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Project 1:&lt;/strong&gt; &lt;code&gt;NEXT_PUBLIC_BASE_PATH=domain-1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project 2:&lt;/strong&gt; &lt;code&gt;NEXT_PUBLIC_BASE_PATH=domain-2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project 3:&lt;/strong&gt; &lt;code&gt;NEXT_PUBLIC_BASE_PATH=domain-3&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;This ensures that each domain pulls the correct content from your CMS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Handling Links in Your Application
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Example: Link Processing Function
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;linkProcessor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IStoryLink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_BASE_PATH&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;correctUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;full_slug&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cached_url&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Remove base path if link is to the homepage&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;correctUrl&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_BASE_PATH&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;correctUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;correctUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_BASE_PATH&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="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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;correctUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;correctUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_BASE_PATH&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="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;correctUrl&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;link&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;full_slug&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cached_url&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function ensures that when users navigate your site, they won’t see URLs like &lt;code&gt;prod-domain.com/domain-1/&lt;/code&gt; but rather the cleaner &lt;code&gt;prod-domain.com/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's all. It's THAT simple. What did you expect, a 10-page guide? Stop reading and go have fun with JavaScript! &lt;strong&gt;Happy hacking&lt;/strong&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Considerations
&lt;/h2&gt;

&lt;p&gt;For more sophisticated readers, here are a few other places where you can use this in your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sitemap Generation
&lt;/h3&gt;

&lt;p&gt;First of all, don't forget your roots. In our case, it's a sitemap. The main thing you should do is add this &lt;code&gt;NEXT_PUBLIC_BASE_PATH&lt;/code&gt; to &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_PRODUCTION_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//prod-domain.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your sitemap generation script (&lt;code&gt;generateSitemap.ts&lt;/code&gt;), modify the slug to remove the base path:&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;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;full_slug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_BASE_PATH&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="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;slugWithoutTrailingSlash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`\n&amp;lt;url&amp;gt;\n&amp;lt;loc&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_PRODUCTION_DOMAIN&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="nx"&gt;slugWithoutTrailingSlash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/loc&amp;gt;
&amp;lt;lastmod&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/lastmod&amp;gt;&amp;lt;/url&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Configuring Redirects and Rewrites
&lt;/h3&gt;

&lt;p&gt;You can also control redirects, rewrites, or other configurations based on the domain:&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;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_BASE_PATH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;domain-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;redirects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_REDIRECTS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;DOMAIN_1_REDIRECTS&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;rewrites&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_REWRITES&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="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;redirects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_REDIRECTS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;rewrites&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_REWRITES&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Managing Tracking Scripts
&lt;/h3&gt;

&lt;p&gt;Lastly, use the environment variable to manage domain-specific tracking scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Script&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tracking-script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lazyOnload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.tracking_script.com/script/ididid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_BASE_PATH&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;domain-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;first-domain-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;domain-2.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that your tracking data is accurately associated with the correct domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multilanguage
&lt;/h2&gt;

&lt;p&gt;You may ask yourself, "What about multilanguage support?" Fear not! Storyblok has you covered. By following the same principles discussed here, you can easily manage multilanguage content across multiple domains. Simply create folders for each language and domain, and you're good to go.&lt;/p&gt;

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

&lt;p&gt;If you wish for more control over multilanguage settings, you can create a &lt;code&gt;configuration&lt;/code&gt; folder with a &lt;code&gt;languages&lt;/code&gt; subfolder. In this subfolder, create stories for each language with any settings you can imagine. Just fetch this data like we did in the &lt;strong&gt;Step 2&lt;/strong&gt; example, and you're all set!&lt;/p&gt;

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

&lt;p&gt;Another question you might have is, "Hey, what if some of my domains are multilanguage, and others aren't?" No worries! You can mix and match as needed. Storyblok's flexible structure allows you to adapt to various scenarios seamlessly.&lt;/p&gt;

&lt;p&gt;For example, you can create &lt;code&gt;configuration&lt;/code&gt; folder with &lt;code&gt;domains-settings&lt;/code&gt; subfolder which will have stories for each domain with settings like &lt;code&gt;isUsingLocales&lt;/code&gt; and &lt;code&gt;defaultHomepageSlug&lt;/code&gt;: &lt;/p&gt;

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

&lt;p&gt;Also, don't forget about Storyblok built-in conditional fields. They can be a lifesaver when you need to show or hide some fields from content managers.&lt;/p&gt;

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

&lt;p&gt;You can fetch this configuration in your application and use it to determine how to handle multilanguage content for each domain. The possibilities are endless!&lt;/p&gt;

&lt;h3&gt;
  
  
  That's all, folks!
&lt;/h3&gt;

&lt;p&gt;And there you have it! With Storyblok and a bit of JavaScript magic, you can manage multiple domains under one CMS space with ease. So go forth and build amazing projects that span the digital realm. &lt;strong&gt;Happy hacking&lt;/strong&gt;!&lt;/p&gt;

</description>
      <category>multidomain</category>
      <category>nextjs</category>
      <category>storyblok</category>
      <category>vercel</category>
    </item>
    <item>
      <title>Vercel vs Netlify: How to Pick the Right One</title>
      <dc:creator>Alex Hramovich</dc:creator>
      <pubDate>Mon, 26 Aug 2024 08:37:43 +0000</pubDate>
      <link>https://dev.to/focusreactive/vercel-vs-netlify-how-to-pick-the-right-one-d1e</link>
      <guid>https://dev.to/focusreactive/vercel-vs-netlify-how-to-pick-the-right-one-d1e</guid>
      <description>&lt;p&gt;In today’s web development, choosing the right deployment platform is key to your project's performance, scalability, and ease of management. Vercel and Netlify stand out as top choices for developers building web applications efficiently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing Between Vercel and Netlify: What You Need to Know
&lt;/h3&gt;

&lt;p&gt;When it comes to static site hosting and serverless deployment, Vercel and Netlify are top contenders, both built around the Jamstack architecture. They excel at delivering pre-rendered static content from CDNs, while adding dynamic capabilities through APIs and serverless functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Vercel&lt;/strong&gt; if you need lightning-fast global content delivery, especially for projects built with Next.js. Vercel’s deep integration with Next.js and strong support for server-side rendering (SSR) make it an excellent choice for dynamic content and SEO-driven sites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go with Netlify&lt;/strong&gt; if you're looking for a great ecosystem packed with built-in tools like form handling, identity management, and a versatile deployment suite. Netlify, as one of the original pioneers of Jamstack, is perfect for static sites that can leverage its rich set of integrated features.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Decision Tree&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here’s a simple decision tree to help guide your platform choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Do you need Server-Side Rendering (SSR)?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yes&lt;/strong&gt; → Choose &lt;strong&gt;Vercel&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No&lt;/strong&gt; → Move to the next question&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Are you using Next.js or prioritizing edge performance?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yes&lt;/strong&gt; → Choose &lt;strong&gt;Vercel&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No&lt;/strong&gt; → Move to the next question&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Do you need built-in form handling, identity management, or A/B testing?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yes&lt;/strong&gt; → Choose &lt;strong&gt;Netlify&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No&lt;/strong&gt; → Move to the next question&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Is pricing flexibility and built-in features important to you?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yes&lt;/strong&gt; → Choose &lt;strong&gt;Netlify&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No&lt;/strong&gt; → Move to the next question&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Do you prefer using Docker for builds?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yes&lt;/strong&gt; → Choose &lt;strong&gt;Netlify&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No&lt;/strong&gt; → Choose &lt;strong&gt;Vercel&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Comparison of Vercel and Netlify&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To make a smart decision between Vercel and Netlify, it's important to look at how they stack up in the areas that matter most for your project. In case you're interested, here is a &lt;a href="https://focusreactive.com/vercel-vs-netlify-how-to-pick-the-right-platform/" rel="noopener noreferrer"&gt;detailed Vercel vs Netlify comparison&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vercel</category>
      <category>netlify</category>
      <category>jamstack</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>7 Awesome Multi-Tenant Features in Headless CMS That'll Make Your Life Easier</title>
      <dc:creator>Oleg Proskurin</dc:creator>
      <pubDate>Sat, 24 Aug 2024 12:15:00 +0000</pubDate>
      <link>https://dev.to/focusreactive/7-awesome-multi-tenant-features-in-headless-cms-thatll-make-your-life-easier-2haa</link>
      <guid>https://dev.to/focusreactive/7-awesome-multi-tenant-features-in-headless-cms-thatll-make-your-life-easier-2haa</guid>
      <description>&lt;p&gt;Headless CMS platforms are not only matching traditional content management systems but are significantly surpassing them. These systems offer advanced multi-tenant features that traditional CMS platforms lack. Ready to enhance your web strategy? Let's delve into seven features that can transform your content management experience.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multilingual Content Management&lt;/strong&gt; 🌍&lt;br&gt;&lt;br&gt;
Eliminate language barriers effortlessly. Headless CMS platforms enable you to manage content in multiple languages within a single interface, making it seamless to reach a global audience. It's like hosting an international conference within your CMS. Learn more about &lt;a href="https://focusreactive.com/multiple-domains-with-a-headless-cms/#multilanguage" rel="noopener noreferrer"&gt;setting up a multilingual project in Storyblok&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Domain Support&lt;/strong&gt; 🏢&lt;br&gt;&lt;br&gt;
Managing multiple brands or clients? Headless CMS provides centralized control over several domains from one hub. It's akin to having a Swiss Army knife for websites—multiple tools in one compact package. Discover how to &lt;a href="https://focusreactive.com/multiple-domains-with-a-headless-cms/#the-scenario-managing-multiple-domains" rel="noopener noreferrer"&gt;configure a multi-domain setup with Vercel, NextJS, and Storyblok&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Regional Content Delivery&lt;/strong&gt; 🗺️&lt;br&gt;&lt;br&gt;
Go beyond translation by tailoring your content for different countries or regions, ensuring your message resonates with local audiences. This feature also helps navigate varying governmental requirements across countries or even states—crucial in industries like iGaming. Explore how we established CMS &lt;a href="https://focusreactive.com/sanity-cms-for-tipico-platform/#1-the-labels-system" rel="noopener noreferrer"&gt;sections for U.S. states in Sanity&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Built-In A/B Testing&lt;/strong&gt; 🧪&lt;br&gt;&lt;br&gt;
Some Headless CMS platforms include integrated A/B testing capabilities. Experiment with different content versions to optimize engagement, providing insights into what your audience prefers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Personalized Content Delivery&lt;/strong&gt; 🎭&lt;br&gt;&lt;br&gt;
Imagine a CMS that delivers content based on user behavior and interests. This feature enhances user experience by providing relevant content. Learn how &lt;a href="https://focusreactive.com/modern-ecommerce-architecture-trends-and-services-a-comprehensive-guide/#24-getting-personal-using-data-to-improve-shopping-experiences" rel="noopener noreferrer"&gt;personalization can be implemented&lt;/a&gt; to improve engagement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Omnichannel Content Distribution&lt;/strong&gt; 📱&lt;br&gt;&lt;br&gt;
Distribute your content across websites, mobile apps, smart devices, and more, ensuring consistency and broad reach. This is especially beneficial for eCommerce platforms, maintaining product presentation across various channels. Read more about &lt;a href="https://focusreactive.com/modern-ecommerce-architecture-trends-and-services-a-comprehensive-guide/#23-omnichannel-retail-blending-online-and-offline-shopping" rel="noopener noreferrer"&gt;omnichannel retail and blending online and offline shopping&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customizable User Roles and Permissions&lt;/strong&gt; 🔐&lt;br&gt;&lt;br&gt;
Define who has access to what within your CMS. You can grant limited access to external contributors, perfect for collaborations without compromising security. See how you can &lt;a href="https://focusreactive.com/assigning-cms-users-to-sanity/" rel="noopener noreferrer"&gt;assign CMS users in Sanity&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These multi-tenant features showcase how Headless CMS is redefining content management. It's about creating dynamic experiences across multiple platforms and audiences.&lt;/p&gt;

&lt;p&gt;Development with Headless CMS is often more straightforward than you might think. It excels in performance and SEO optimization—key factors that make your website stand out in today's digital landscape.&lt;/p&gt;

&lt;p&gt;At FocusReactive, we've witnessed businesses transform with these features. Our team specializes in platforms like Storyblok and Sanity and is dedicated to helping you unlock their full potential.&lt;/p&gt;

&lt;p&gt;Interested in learning how to set up a multi-tenant Headless CMS project using Storyblok, NextJS, and Vercel? Refer to our comprehensive &lt;a href="https://focusreactive.com/multiple-domains-with-a-headless-cms/" rel="noopener noreferrer"&gt;technical guide on the FocusReactive blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ready to elevate your web presence with multi-tenant Headless CMS? Let's &lt;a href="https://focusreactive.com/#mail-us" rel="noopener noreferrer"&gt;discuss your project&lt;/a&gt; and how we can help you achieve digital excellence. The future of content management is here—are you ready to embrace it?&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>headless</category>
      <category>storyblok</category>
      <category>webdev</category>
    </item>
    <item>
      <title>7 Key eCommerce Trends for 2024 You Need to Know</title>
      <dc:creator>Oleg Proskurin</dc:creator>
      <pubDate>Mon, 12 Aug 2024 08:19:07 +0000</pubDate>
      <link>https://dev.to/focusreactive/7-key-ecommerce-trends-for-2024-you-need-to-know-422j</link>
      <guid>https://dev.to/focusreactive/7-key-ecommerce-trends-for-2024-you-need-to-know-422j</guid>
      <description>&lt;p&gt;Through our research on modern eCommerce, we have identified key trends shaping the industry. For a comprehensive overview, please read our full article on &lt;a href="https://focusreactive.com/modern-ecommerce-architecture-trends-and-services-a-comprehensive-guide/" rel="noopener noreferrer"&gt;Modern eCommerce Architecture Trends and Services&lt;/a&gt;. Below is a concise summary of the primary trends, including their business benefits and additional features.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. AI-Driven Personalization
&lt;/h4&gt;

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

&lt;p&gt;Learn more about &lt;a href="https://focusreactive.com/modern-ecommerce-architecture-trends-and-services-a-comprehensive-guide/#21-ai-making-online-shopping-smarter" rel="noopener noreferrer"&gt;AI Making Online Shopping Smarter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Artificial Intelligence enhances customer experience through machine learning algorithms, predictive analytics, and customized user interactions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Benefits&lt;/strong&gt;: Increased conversions, enhanced customer experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive Edge&lt;/strong&gt;: Small apparel shops can use AI to recommend outfits based on customer preferences, leading to higher sales.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.dynamicyield.com/" rel="noopener noreferrer"&gt;Dynamic Yield&lt;/a&gt;&lt;/strong&gt; — AI personalization platform that tailors content, products, and offers to each customer's preferences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://useinsider.com/ai-personalization-tools/" rel="noopener noreferrer"&gt;Insider&lt;/a&gt;&lt;/strong&gt; — AI-powered personalization tool for websites, apps, email, and more.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Integration&lt;/strong&gt;: Medium complexity, requires data infrastructure and expertise.&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. AR and VR Shopping Experiences
&lt;/h4&gt;

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

&lt;p&gt;Discover how &lt;a href="https://focusreactive.com/modern-ecommerce-architecture-trends-and-services-a-comprehensive-guide/#22-ar-and-vr-bringing-online-shopping-to-life" rel="noopener noreferrer"&gt;AR and VR are Bringing Online Shopping to Life&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;AR and VR technologies bring products to life, allowing customers to virtually try on products or visualize them in their environment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Benefits&lt;/strong&gt;: Reduced returns, increased customer confidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive Edge&lt;/strong&gt;: Dress shops can use VR to allow customers to try on dresses virtually before purchasing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.zakeke.com/" rel="noopener noreferrer"&gt;Zakeke&lt;/a&gt;&lt;/strong&gt; — 3D product configurator and customizer plugin for eCommerce, allowing customers to craft their dream products.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.threekit.com/" rel="noopener noreferrer"&gt;Threekit&lt;/a&gt;&lt;/strong&gt; — Visual product configurator for brands and manufacturers, enabling 3D configuration, virtual photography, and augmented reality.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Integration&lt;/strong&gt;: High complexity, requires AR/VR development skills.&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Omnichannel Retail Integration
&lt;/h4&gt;

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

&lt;p&gt;Explore how &lt;a href="https://focusreactive.com/modern-ecommerce-architecture-trends-and-services-a-comprehensive-guide/#23-omnichannel-retail-blending-online-and-offline-shopping" rel="noopener noreferrer"&gt;Omnichannel Retail is Blending Online and Offline Shopping&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Omnichannel strategies blend online and offline shopping, providing a seamless experience across all platforms.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Benefits&lt;/strong&gt;: Improved customer loyalty, consistent brand experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive Edge&lt;/strong&gt;: A local bookstore can integrate online and offline shopping for a unified customer experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://help.shopify.com/en/manual/intro-to-shopify/pricing-plans/plans-features/shopify-plus-plan" rel="noopener noreferrer"&gt;Shopify Plus&lt;/a&gt;&lt;/strong&gt; — Offers features like unlimited staff accounts, customizable checkout, and expansion stores to support high-volume businesses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://magicfuse.co/blog/what-is-salesforce-commerce-cloud/" rel="noopener noreferrer"&gt;Salesforce Commerce Cloud&lt;/a&gt;&lt;/strong&gt; — Provides tools, mobile frameworks, and features to create responsive eCommerce websites and deliver personalized customer experiences across channels.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Integration&lt;/strong&gt;: Medium complexity, requires unified data management.&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  4. Data-Driven Personalization
&lt;/h4&gt;

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

&lt;p&gt;Find out more about &lt;a href="https://focusreactive.com/modern-ecommerce-architecture-trends-and-services-a-comprehensive-guide/#24-getting-personal-using-data-to-improve-shopping-experiences" rel="noopener noreferrer"&gt;Using Data to Improve Shopping Experiences&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Utilizing customer data to create personalized shopping experiences enhances engagement and satisfaction.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Benefits&lt;/strong&gt;: Better customer insights, increased sales.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive Edge&lt;/strong&gt;: A coffee shop can tailor its offerings based on customer purchase history and preferences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://segment.com/" rel="noopener noreferrer"&gt;Segment&lt;/a&gt;&lt;/strong&gt; — Customer data platform that collects, unifies, and activates customer data across the stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.optimizely.com/" rel="noopener noreferrer"&gt;Optimizely&lt;/a&gt;&lt;/strong&gt; — Digital experience platform that enables A/B testing, feature flagging, and personalization.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Integration&lt;/strong&gt;: Medium complexity, requires robust data analytics capabilities.&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  5. Advanced Delivery Solutions
&lt;/h4&gt;

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

&lt;p&gt;Learn about &lt;a href="https://focusreactive.com/modern-ecommerce-architecture-trends-and-services-a-comprehensive-guide/#25-getting-your-stuff-faster-the-future-of-delivery" rel="noopener noreferrer"&gt;The Future of Delivery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Innovations in last-mile delivery, such as autonomous vehicles and drone deliveries, speed up and streamline the delivery process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Benefits&lt;/strong&gt;: Faster deliveries, reduced costs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive Edge&lt;/strong&gt;: A local grocery store can offer drone deliveries for quicker and more efficient service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.starship.xyz/" rel="noopener noreferrer"&gt;Starship Technologies&lt;/a&gt;&lt;/strong&gt; — Autonomous robot delivery service that makes food and package deliveries more efficient, convenient, and sustainable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://mttr.net/" rel="noopener noreferrer"&gt;Matternet&lt;/a&gt;&lt;/strong&gt; — Drone delivery platform that enables on-demand delivery of medical supplies and other goods.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Integration&lt;/strong&gt;: High complexity, regulatory challenges.&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  6. Mobile Commerce Expansion
&lt;/h4&gt;

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

&lt;p&gt;Explore &lt;a href="https://focusreactive.com/modern-ecommerce-architecture-trends-and-services-a-comprehensive-guide/#26-shopping-in-your-pocket-the-mobile-commerce-boom" rel="noopener noreferrer"&gt;The Mobile Commerce Boom&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The rise of mobile commerce is supported by technologies like Progressive Web Apps (PWAs) and mobile payment solutions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Benefits&lt;/strong&gt;: Higher conversion rates, improved user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive Edge&lt;/strong&gt;: Small boutiques can leverage mobile commerce to reach customers on the go.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://stripe.com/" rel="noopener noreferrer"&gt;Stripe&lt;/a&gt;&lt;/strong&gt; — Online payment processing platform that supports mobile payments, including Apple Pay and Google Pay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.braintreepayments.com/" rel="noopener noreferrer"&gt;Braintree&lt;/a&gt;&lt;/strong&gt; — PayPal-owned payment gateway that offers mobile SDKs and supports one-touch checkout.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Integration&lt;/strong&gt;: Low complexity, primarily front-end development.&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  7. Subscription-Based Models
&lt;/h4&gt;

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

&lt;p&gt;Learn more about &lt;a href="https://focusreactive.com/modern-ecommerce-architecture-trends-and-services-a-comprehensive-guide/#27-subscription-based-e-commerce-models" rel="noopener noreferrer"&gt;Subscription-Based E-Commerce Models&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Subscription services offer predictable revenue and personalized customer experiences through curated product boxes and digital content.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Benefits&lt;/strong&gt;: Recurring revenue, increased customer retention.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive Edge&lt;/strong&gt;: Beauty product stores can offer subscription boxes with personalized selections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://getrecharge.com/features/" rel="noopener noreferrer"&gt;ReCharge&lt;/a&gt;&lt;/strong&gt; — Subscription management platform that powers recurring orders for over 100 million subscribers globally, offering features like custom checkout domains and discount code analytics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://boldcommerce.com/shopify/subscriptions" rel="noopener noreferrer"&gt;Bold Subscriptions&lt;/a&gt;&lt;/strong&gt; — Shopify app that enables subscription-based business models, with features like recurring payments, subscriber management, and flexible subscription options.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Integration&lt;/strong&gt;: Medium complexity, requires subscription management systems.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;We are thrilled to share our insights and knowledge with you. For more in-depth content, visit our blog on &lt;a href="https://focusreactive.com/blog/category/headless-commerce/" rel="noopener noreferrer"&gt;Headless Commerce&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>storefront</category>
      <category>ecommerce</category>
      <category>webdev</category>
      <category>composable</category>
    </item>
    <item>
      <title>How to Survive If You Still Have a Traditional CMS</title>
      <dc:creator>Oleg Proskurin</dc:creator>
      <pubDate>Mon, 12 Aug 2024 06:16:39 +0000</pubDate>
      <link>https://dev.to/focusreactive/how-to-survive-if-you-still-have-a-traditional-cms-1860</link>
      <guid>https://dev.to/focusreactive/how-to-survive-if-you-still-have-a-traditional-cms-1860</guid>
      <description>&lt;p&gt;Let's face it: if you're still using a traditional CMS like Drupal, you're basically riding a dinosaur in the age of electric cars. Sure, it gets the job done (sort of), but is it really the best you can do for your business? It's time to talk about headless CMS and why you should make the switch before your competitors leave you in the dust.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Traditional CMS Is Becoming Obsolete
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lack of Flexibility&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Traditional CMS platforms tie your content and presentation together, making it tough to deliver content across different platforms. Want to reuse that fantastic blog post for your app? Good luck!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance Issues&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Monolithic systems can be slow, and in today's fast-paced world, a slow website is a sure way to lose visitors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security Vulnerabilities&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Traditional CMS platforms are frequent targets for hackers. With every new plugin or update, there's a potential new security hole.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability Challenges&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
As your business grows, your CMS needs to grow too. Traditional CMS often struggle with scaling efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inconsistent Omnichannel Experience&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Providing a consistent experience across various channels (web, mobile, IoT) is a nightmare with traditional CMS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Competitive Advantages of Switching to Headless CMS
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Flexibility and Freedom&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Headless CMS separates the backend from the frontend, allowing developers to use any technology stack they prefer. This means you can deliver content wherever and however you want.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enhanced Performance&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
APIs deliver content quickly, ensuring your users enjoy a fast and seamless experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improved Security&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Decoupling the backend from the frontend minimizes security risks. Updates can be made without breaking the frontend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better Scalability&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Headless CMS can grow with your business. Adding new content types or channels is a breeze.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Omnichannel Experience&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Easily repurpose and distribute content across multiple platforms, ensuring a unified brand experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple and Painless Migration Options
&lt;/h3&gt;

&lt;p&gt;Ready to make the switch? Here are some modern headless CMS options to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sanity&lt;/strong&gt;: Known for its real-time collaboration and flexible content modeling. &lt;a href="https://focusreactive.com/migration-from-drupal/#sanity" rel="noopener noreferrer"&gt;Sanity&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storyblok&lt;/strong&gt;: Offers a visual editor and a component-based approach for creating reusable content blocks. &lt;a href="https://focusreactive.com/migration-from-drupal/#storyblok" rel="noopener noreferrer"&gt;Storyblok&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contentful&lt;/strong&gt;: Provides a robust API and extensive integration capabilities. &lt;a href="https://focusreactive.com/migration-from-drupal/#contentful" rel="noopener noreferrer"&gt;Contentful&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Directus&lt;/strong&gt;: An open-source option that offers a dynamic API and customizable dashboard. &lt;a href="https://focusreactive.com/migration-from-drupal/#directus" rel="noopener noreferrer"&gt;Directus&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payload&lt;/strong&gt;: Focuses on developer experience with a fully extendable and customizable backend. &lt;a href="https://focusreactive.com/migration-from-drupal/#payload-cms" rel="noopener noreferrer"&gt;Payload&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, we strongly recommend working with an experienced agency to ensure a smooth and successful migration. These experts can help you navigate the complexities and get your new system up and running without a hitch.&lt;/p&gt;

&lt;p&gt;Headless CMS is transforming the way we manage and deliver content. By adopting this modern approach, businesses can achieve greater flexibility, performance, and security while scaling seamlessly across multiple channels. For a comprehensive guide on migrating from Drupal to a headless CMS, check out the full article &lt;a href="https://focusreactive.com/migration-from-drupal/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>cms</category>
      <category>headless</category>
      <category>migration</category>
      <category>webdev</category>
    </item>
    <item>
      <title>6 Effective Ways to Load Content in Modern Static Sites with Next.js v14 page router</title>
      <dc:creator>Oleg Proskurin</dc:creator>
      <pubDate>Mon, 12 Aug 2024 05:42:14 +0000</pubDate>
      <link>https://dev.to/focusreactive/6-effective-ways-to-load-content-in-modern-static-sites-with-nextjs-v14-page-router-12fm</link>
      <guid>https://dev.to/focusreactive/6-effective-ways-to-load-content-in-modern-static-sites-with-nextjs-v14-page-router-12fm</guid>
      <description>&lt;p&gt;Arthur Nikitsin, a seasoned developer at FocusReactive, has published an insightful article on &lt;a href="https://focusreactive.com/what-is-a-static-website/" rel="noopener noreferrer"&gt;static site generation&lt;/a&gt;. But even static websites can leverage various content-loading methods for enhanced performance and flexibility. In this overview, we'll explore six effective methods available in Next.js v14 using the pages router. These methods ensure optimal performance and user experience, even with SSG. Note that the app router offers more flexibility, but is recommended to wait for the stable release in v15.&lt;/p&gt;

&lt;p&gt;Check out Arthur's original article for a detailed dive into static site generation.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Static Site Generation (SSG)
&lt;/h4&gt;

&lt;p&gt;Generates HTML at build time and reuses it for each request. Ideal for pages with content that doesn’t change often. This is the primary method used in static site generation.&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;// pages/index.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getStaticProps&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;data&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;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&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="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; For static content like blogs or documentation.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;getStaticProps&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; Fetches data at build time, creating HTML that is served on every request.&lt;br&gt;&lt;br&gt;
&lt;a href="https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props" rel="noopener noreferrer"&gt;Read more about SSG&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Server-Side Rendering (SSR)
&lt;/h4&gt;

&lt;p&gt;Generates HTML on each request, useful for dynamic content.&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;// pages/index.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getServerSideProps&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;data&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;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&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="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; For frequently changing data.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;getServerSideProps&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; Fetches data on every request, rendering HTML dynamically.&lt;br&gt;&lt;br&gt;
&lt;a href="https://nextjs.org/docs/pages/building-your-application/data-fetching/get-server-side-props" rel="noopener noreferrer"&gt;Read more about SSR&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Client-Side Rendering (CSR)
&lt;/h4&gt;

&lt;p&gt;Data is fetched and rendered on the client side, which can be beneficial even for static sites. This method is useful when you need to update parts of the page based on user interactions without a full page reload.&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;// pages/index.js&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchData&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setData&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="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;fetchData&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;&lt;strong&gt;When to use:&lt;/strong&gt;  For interactive elements like forms, real-time data, or personalized content that updates after the initial page load. &lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;useEffect&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; Fetches data in the browser after the initial load, allowing for dynamic updates without a full reload. This enhances user experience by providing instant feedback or updates based on user interactions.&lt;br&gt;
&lt;a href="https://nextjs.org/docs/pages/building-your-application/data-fetching/client-side" rel="noopener noreferrer"&gt;Read more about CSR&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  4. Code Splitting
&lt;/h4&gt;

&lt;p&gt;Dynamically imports parts of code to optimize load time. Code splitting can also be used for lazy loading components (see the next point).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/dynamic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DynamicComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/DynamicComponent&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;&lt;strong&gt;When to use:&lt;/strong&gt; To improve performance by loading only necessary code.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;next/dynamic&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; Loads code chunks on demand, reducing initial load time.&lt;br&gt;&lt;br&gt;
&lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading" rel="noopener noreferrer"&gt;Read more about Code Splitting&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  5. Lazy Loading Components
&lt;/h4&gt;

&lt;p&gt;Defers loading of offscreen components until needed, enhancing performance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/dynamic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DynamicHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/header&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;loading&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&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;DynamicHeader&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;&lt;strong&gt;When to use:&lt;/strong&gt; For components not immediately in view.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;React.lazy&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; Loads components when they are about to enter the viewport.&lt;br&gt;&lt;br&gt;
&lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading" rel="noopener noreferrer"&gt;Read more about Lazy Loading Components&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  6. Lazy Loading Images
&lt;/h4&gt;

&lt;p&gt;By default, the &lt;code&gt;next/image&lt;/code&gt; component uses lazy loading for images. The &lt;code&gt;priority&lt;/code&gt; prop can be used to disable lazy loading when necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Image&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/image&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;MyComponent&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt;
    &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/path/to/image.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;priority&lt;/span&gt; &lt;span class="c1"&gt;// use it to disable lazy loading&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;&lt;strong&gt;When to use:&lt;/strong&gt; To optimize page speed with many images.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;next/image&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; Defers image loading until they are needed, reducing initial load time.&lt;br&gt;&lt;br&gt;
&lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/images" rel="noopener noreferrer"&gt;Read more about lazy loading images&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;These methods in Next.js v14 can significantly improve your static site's performance and user experience. For more detailed insights, read Arthur Nikitsin's full article. You can explore more of his work &lt;a href="https://focusreactive.com/blog/author/ArturNikitsin/" rel="noopener noreferrer"&gt;in our company blog&lt;/a&gt;.&lt;/p&gt;

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