<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/atom-premium.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:media="http://search.yahoo.com/mrss/" xmlns:podcast="https://podcastindex.org/namespace/1.0">
  <feedpress:locale>en</feedpress:locale>
  <feedpress:newsletterId>telerik-blogs-web</feedpress:newsletterId>
  <link rel="hub" href="https://feedpress.superfeedr.com/"/>
  <logo>https://static.feedpress.com/logo/telerik-blogs--web-5ab52bef0a72f.jpg</logo>
  <title type="text">Telerik Blogs | Web</title>
  <subtitle type="text">The official blog of Progress Telerik - expert articles and tutorials for developers.</subtitle>
  <id>uuid:d536280c-5815-417a-ba64-256497ab1ae3;id=2942</id>
  <updated>2026-07-14T00:42:49Z</updated>
  <link rel="alternate" href="https://www.telerik.com/"/>
  <link rel="self" type="application/atom+xml" href="https://feeds.telerik.com/blogs/web"/>
  <entry>
    <id>urn:uuid:4a36cd67-245a-4a88-b882-b91cad15ebb8</id>
    <title type="text">Introduction to Agent Authentication and Authorization on Mastra Using Firebase</title>
    <summary type="text">Explore how to secure agents built with Mastra, using a demo Next.js application integrated with a simple Mastra agent and authentication and authorization in Firebase.</summary>
    <published>2026-07-13T13:34:05Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Christian Nwamba </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17379534/introduction-agent-authentication-authorization-mastra-using-firebase"/>
    <content type="text"><![CDATA[<p><span class="featured">Explore how to secure agents built with Mastra, using a demo Next.js application integrated with a simple Mastra agent and authentication and authorization in Firebase.</span></p><p>AI agents have moved beyond the experimental stage and are now being deployed in real-world applications. Unlike a traditional API endpoint, an agent can reason, make decisions and handle complex tasks on behalf of a user. This shift is exciting, but it raises important concerns about knowing exactly who is calling an agent and what they are allowed to do.</p><p>When an agent is built and deployed, it can be directly accessed by anyone. This can result in wrongful consumption of API credits, and it poses a significant risk in use cases where the agent is connected to sensitive tools such as databases, file systems and email systems. This is where authentication and authorization come into play. It is important to implement such security protocols to verify the identity and permissions of an agent&rsquo;s users.</p><p>In this article, we&rsquo;ll explore how to secure agents built with <a target="_blank" href="https://mastra.ai/">Mastra</a>, a framework for building agents and other AI-powered applications. We&rsquo;ll build a demo Next.js application integrated with a simple Mastra agent, then implement authentication and authorization using Firebase.</p><h2 id="prerequisites">Prerequisites</h2><p>To follow along with this article, you should have:</p><ul><li>Node.js v22.13.0 or later installed</li><li>Basic knowledge of <a target="_blank" href="https://react.dev/">React</a> and <a target="_blank" href="https://nextjs.org/">Next.js</a></li><li>A Google account to set up <a target="_blank" href="https://firebase.google.com/">Firebase</a></li><li>An API key from a <a target="_blank" href="https://mastra.ai/models/providers/">supported model provider</a></li></ul><h2 id="why-security-matters-for-ai-agents">Why Security Matters for AI Agents</h2><p>To understand why security matters here, let&rsquo;s first understand what an AI agent actually is and how it differs from a regular application. A traditional application is fixed in its behavior. When an API endpoint is called, it runs a fixed block of code and returns a predictable response. There is no reasoning, no decision-making or any action other than what was explicitly programmed.</p><p>An AI agent is quite different. Instead of following a fixed preset, an agent receives an open-ended instruction and figures out how to fulfill it. It can reason about a problem, decide which tools to use, call those tools, interpret the results and take further action, all in a single interaction.</p><p>Now let&rsquo;s talk about security. When you expose an API endpoint, you know exactly what it can do. On the other hand, when you expose an agent, the surface area is much wider. An agent connected to a database can read and write records. An agent connected to email can send messages on someone&rsquo;s behalf. An agent connected to a payment system can initiate transactions. If an unauthorized person reaches that agent, they could potentially instruct it to do any of those things.</p><p>The more capable an agent is, the more important it is to control who can reach it and what it can be asked to do. Also, note that calls to AI agents mostly come at the expense of API credits, so it is important to regulate usage in order to avoid incurring unnecessary costs.</p><h2 id="authentication-and-authorization">Authentication and Authorization</h2><p>These two words are often used interchangeably and misplaced for each other. However, they mean different things and solve different problems.</p><p>Authentication answers the question &ldquo;Who are you?&rdquo; It verifies the identity of the person making a request. Generally, a user signs in, proves who they are, and receives a token that proves their identity on subsequent requests.</p><p>Authorization answers the question &ldquo;What are you allowed to do?&rdquo; It verifies that the authenticated user actually has permission to perform the action they&rsquo;re requesting.</p><h2 id="why-firebase">Why Firebase?</h2><p>There are different ways to implement authentication and authorization on Mastra AI agents. In this article, we are using Firebase for several reasons. First, Firebase is a fully managed service. It abstracts away the complexity of OAuth flows, token signing, token expiration, session management and much more.</p><p>Next, with <a target="_blank" href="https://firebase.google.com/docs/firestore">Firebase&rsquo;s Firestore</a>, we don&rsquo;t need to set up a separate database just to store and manage user roles. Firestore is a natural place to store user roles because it is already in the Firebase ecosystem. Firestore also has built-in security rules, which means we can control and manage access.</p><p>Finally, Mastra has first-class support for Firebase through the @mastra/auth-firebase package. This means that protecting Mastra&rsquo;s own internal server endpoints is straightforward and requires very little configuration.</p><h2 id="demo-setup">Demo Setup</h2><p>So far, we&rsquo;ve touched briefly on what AI agents are, the need for security and why we&rsquo;re using Firebase in this article. We can now start building our demo application to see how authentication and authorization can be implemented on Mastra AI agents using Firebase.</p><p>For the demo, we&rsquo;ll build a simple prompt-and-response application that integrates with a Mastra agent under the hood. We&rsquo;ll configure security beyond just agent protection. Security here is applied in four different layers.</p><p>Layer 1 redirects all unauthenticated users to the login page. At Layer 2, every request to the API route must carry a valid Firebase token. If it doesn&rsquo;t, the request is rejected with a 401 error before anything else happens. This cannot be bypassed in the browser because it runs entirely on the server.</p><p>At Layer 3, once the token is verified and the server knows who the user is, it checks their role in Firestore. If their role does not qualify, the request is rejected with a 403 error. At this point, the agent has not even been triggered.</p><p>Layer 4, which is the core of this article, uses the <code>MastraAuthFirebase</code> class to apply the same Firebase token verification to Mastra&rsquo;s own endpoints. Note that this security configuration can be approached in different ways. The most important thing is to properly define the <code>MastraAuthFirebase</code> class.</p><p>To get started, run the command below in your terminal to create a new Next.js application:</p><pre class=" language-shell"><code class="prism  language-shell">npx create-next-app@latest test-nextjs-agent
</code></pre><p>This creates a project called <code>test-nextjs-agent</code>. Feel free to rename the project, and complete the resulting prompts as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/project-setup.png?sfvrsn=d24c7dfd_2" title="Next.js Project setup" alt="Next.js Project setup" /></p><p>Run the following commands to navigate into the newly created project and start the development server:</p><pre class=" language-shell"><code class="prism  language-shell">cd test-nextjs-agent
npm run dev
</code></pre><h2 id="initialize-mastra">Initialize Mastra</h2><p>Open a new terminal and run the code below to initialize Mastra:</p><pre class=" language-shell"><code class="prism  language-shell">npx mastra@latest init
</code></pre><p>This installs the Mastra core dependencies and scaffolds the necessary folders and configurations without generating a new project from scratch.</p><p>In the resulting prompt when you run the command above, select a default model provider from the list provided. Here, we&rsquo;ll use Google, but you can select any other provider of your choice.</p><p>There is also a prompt to provide the API key for the selected provider. Since we&rsquo;re using Google, you can create and retrieve a new API key from <a target="_blank" href="https://aistudio.google.com/">Google AI Studio</a>, as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/api-key.png?sfvrsn=30d32657_2" title="Create a new API key in Google AI Studio" alt="Create a new API key in Google AI Studio" /></p><p>You can skip this step, but you&rsquo;ll need to create a .env file and define the API key manually, as shown below:</p><pre class=" language-js"><code class="prism  language-js">GOOGLE_GENERATIVE_AI_API_KEY<span class="token operator">=</span>YOUR<span class="token operator">-</span>GOOGLE<span class="token operator">-</span>API<span class="token operator">-</span>KEY
</code></pre><p>You should now see a new <code>/mastra</code> folder with some predefined files inside the <code>/src</code> folder. It is important to take note of the following files:</p><ul><li><code>/mastra/index.ts</code>: This holds a Mastra instance, imported from <code>@mastra/core/mastra</code>.</li><li><code>/mastra/agents/weather-agent.ts</code>: Holds a test weather agent predefined by the Mastra team. The agent uses the <code>google/gemini-2.5-pro</code> model by default. For testing purposes, you can change that to <code>google/gemini-2.5-flash</code>, which is a less expensive model.</li><li><code>/mastra/tools/weather-tool.ts</code>: Contains a tool that fetches weather data and integrates with the weather agent.</li></ul><p>We can see this agent in action by running this command in the terminal:</p><pre class=" language-shell"><code class="prism  language-shell">npx mastra dev
</code></pre><p>The command starts a server that exposes Mastra Studio and REST endpoints for your agents, tools and workflows. Open <a target="_blank" href="http://localhost:4111/">http://localhost:4111/</a> to access Mastra Studio, which has the test agent ready to be interacted with.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/mastra-studio.png?sfvrsn=8fb29a73_2" title="Mastra Studio" alt="Mastra Studio" /></p><p>Our focus for this article is on agent authentication and authorization in Mastra using Firebase, so we won&rsquo;t consider the inner workings of creating agents, tools, workflows and the rest. Instead, we&rsquo;ll work with this predefined agent. However, you can explore the <a target="_blank" href="https://mastra.ai/docs">official documentation</a> to learn more.</p><h2 id="integrating-mastra-with-next.js">Integrating Mastra with Next.js</h2><p>Since we now have our instance of Mastra up and running, we should be able to call it in our demo Next.js project.</p><p>Let&rsquo;s create a <code>chat</code> API route. Create a <code>src/app/api/chat/route.ts</code> file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> mastra <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/mastra"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> NextResponse <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/server"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">POST</span><span class="token punctuation">(</span>req<span class="token punctuation">:</span> Request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> message <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> req<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>message<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> error<span class="token punctuation">:</span> <span class="token string">"Message is required"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token number">400</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> agent <span class="token operator">=</span> mastra<span class="token punctuation">.</span><span class="token function">getAgent</span><span class="token punctuation">(</span><span class="token string">"weatherAgent"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> agent<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span> role<span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span> content<span class="token punctuation">:</span> message <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> response<span class="token punctuation">:</span> result<span class="token punctuation">.</span>text <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>The code above creates an API route that receives a message and has the agent instance generate a response based on the message. We&rsquo;re intentionally keeping this route simple for demo purposes, with no streaming, memory, thread IDs, etc.</p><p>Next, let&rsquo;s create a simple chat page on the frontend. Replace the contents of your <code>src/app/page.tsx</code> with the following:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token string">"use client"</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Home</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>message<span class="token punctuation">,</span> setMessage<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>response<span class="token punctuation">,</span> setResponse<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> handleSubmit <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>message<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setResponse</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"/api/chat"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
      method<span class="token punctuation">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
      headers<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"Content-Type"</span><span class="token punctuation">:</span> <span class="token string">"application/json"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      body<span class="token punctuation">:</span> JSON<span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setResponse</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex min-h-screen flex-col items-center justify-center p-8 gap-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-2xl font-bold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Weather Agent<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>textarea</span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-full max-w-lg border rounded p-3 text-sm<span class="token punctuation">"</span></span>
        <span class="token attr-name">rows</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">3</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Ask about the weather anywhere...<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>message<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setMessage</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
        <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span></span>
        <span class="token attr-name">disabled</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>loading<span class="token punctuation">}</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-blue-600 text-white px-6 py-2 rounded disabled:opacity-50<span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">{</span>loading <span class="token operator">?</span> <span class="token string">"Thinking..."</span> <span class="token punctuation">:</span> <span class="token string">"Send"</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">{</span>response <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-full max-w-lg border rounded p-4 bg-gray-50 text-sm<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token punctuation">{</span>response<span class="token punctuation">}</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">}</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Here, we created a simple chat page where we can send a message and have the returned response rendered on the screen. Open <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> in your browser to see the updated demo project.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/demo-project-without-authentication.png?sfvrsn=747977f2_2" title="Demo project without authentication" alt="Demo project without authentication" /></p><h2 id="set-up-firebase">Set Up Firebase</h2><p>With our agent up and running, the next step is securing it. Right now, it is completely open, and when deployed, anyone with the URL can interact with it. To fix this, we&rsquo;ll introduce Firebase as our authentication and authorization layer so that only verified users can access both the agent and the demo project as a whole.</p><p>Let&rsquo;s start by setting up and configuring a Firebase project. Go to <a target="_blank" href="https://console.firebase.google.com/">Firebase</a> and create a new Firebase project. You can call it <code>test-nextjs-agent</code> or give it any other name you prefer.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/create-firebase-project.png?sfvrsn=632b292_2" title="Create a new Firebase project" alt="Create a new Firebase project" /></p><p>On the left sidebar in the dashboard, go to <strong>Security</strong> &rarr; <strong>Authentication</strong> and click &ldquo;Get started.&rdquo;</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/firebase-authentication.png?sfvrsn=e1f2690a_2" title="Firebase authentication" alt="Firebase authentication" /></p><p>Enable the Google sign-in provider, set a public-facing name and support email, and then click &ldquo;Save.&rdquo; You can also work with any other provider you prefer. For this demo, we&rsquo;ll use Google.</p><p>Next, in the sidebar, go to <strong>Project Settings</strong> &rarr; <strong>General</strong> tab. Scroll down to &ldquo;Your apps&rdquo; and click the web icon (<code>&lt;/&gt;</code>). Register a web app with any nickname.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/firebase-register-app.png?sfvrsn=9fb3cb25_2" title="Firebase register app" alt="Firebase register app" /></p><p>Firebase will display a <code>firebaseConfig</code> object as shown below. Copy this object and save it, as we&rsquo;ll be using it later:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> firebaseConfig <span class="token operator">=</span> <span class="token punctuation">{</span>
  apiKey<span class="token punctuation">:</span> <span class="token string">"...YOUR-API-KEY"</span><span class="token punctuation">,</span>
  authDomain<span class="token punctuation">:</span> <span class="token string">"test-nextjs-agent.firebaseapp.com"</span><span class="token punctuation">,</span>
  projectId<span class="token punctuation">:</span> <span class="token string">"test-nextjs-agent"</span><span class="token punctuation">,</span>
  <span class="token operator">...</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>Next, go to <strong>Project Settings</strong> and click on the <strong>Service Accounts</strong> tab. Then click to generate a new private key. This will download a JSON file that serves as the server&rsquo;s proof of identity to Firebase.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/generate-new-private-key.png?sfvrsn=88635363_2" title="Firebase generate new private key" alt="Firebase generate new private key" /></p><p>This service account file is very important. It enables server-side access to Firebase. Do not commit it to your project&rsquo;s version control. Move the file to the project&rsquo;s root folder and add it to <code>.gitignore</code> immediately.</p><p>Next, run the command below:</p><pre class=" language-shell"><code class="prism  language-shell">npm install firebase firebase-admin @mastra/auth-firebase
</code></pre><p>This installs the following:</p><ul><li><code>firebase</code>: The Firebase client-side SDK that runs in the browser. Since we&rsquo;re using Google sign-in here, it handles the sign-in pop-up and manages the user&rsquo;s ID token.</li><li><code>firebase-admin</code>: The server-side SDK that runs in Next.js API routes. It verifies that the ID token the browser sent is real and hasn&rsquo;t been tampered with.</li><li><code>@mastra/auth-firebase</code>: Mastra&rsquo;s built-in auth wrapper for Firebase.</li></ul><p>Finally, open the <code>.env</code> file and update the environment variables as shown below:</p><pre class=" language-js"><code class="prism  language-js">GOOGLE_GENERATIVE_AI_API_KEY<span class="token operator">=</span>YOUR<span class="token operator">-</span>GOOGLE<span class="token operator">-</span>API<span class="token operator">-</span>KEY
    
    NEXT_PUBLIC_FIREBASE_API_KEY<span class="token operator">=</span>YOUR<span class="token operator">-</span>FIREBASE<span class="token operator">-</span>API<span class="token operator">-</span>KEY
    NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN<span class="token operator">=</span>test<span class="token operator">-</span>nextjs<span class="token operator">-</span>agent<span class="token punctuation">.</span>firebaseapp<span class="token punctuation">.</span>com
    NEXT_PUBLIC_FIREBASE_PROJECT_ID<span class="token operator">=</span>test<span class="token operator">-</span>nextjs<span class="token operator">-</span>agent
    
    FIREBASE_SERVICE_ACCOUNT<span class="token operator">=</span><span class="token operator">/</span>absolute<span class="token operator">/</span>path<span class="token operator">/</span>to<span class="token operator">/</span>the<span class="token operator">/</span>service<span class="token operator">/</span>account<span class="token operator">/</span>file<span class="token punctuation">.</span>json
</code></pre><p>Here, we included environment variables required for both the frontend and backend. The <code>firebaseConfig</code> object we copied earlier contains the frontend values, while <code>FIREBASE_SERVICE_ACCOUNT</code> is an absolute path to the service account file we downloaded.</p><p>If you&rsquo;re unsure how to get the absolute path, run the command below in the terminal:</p><pre class=" language-shell"><code class="prism  language-shell">pwd
</code></pre><p>Copy the returned path, then append the filename and its extension to form the full file path.</p><h2 id="implementing-firebase-agent-authentication">Implementing Firebase Agent Authentication</h2><p>In this section, we&rsquo;ll see how to implement Firebase authentication across our application, including for our Mastra agent.</p><p>Create a <code>src/lib/firebase.ts</code> file and add the following to it to initialize the Firebase client SDK:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> initializeApp<span class="token punctuation">,</span> getApps<span class="token punctuation">,</span> getApp <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"firebase/app"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> getAuth<span class="token punctuation">,</span> GoogleAuthProvider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"firebase/auth"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> firebaseConfig <span class="token operator">=</span> <span class="token punctuation">{</span>
  apiKey<span class="token punctuation">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span>NEXT_PUBLIC_FIREBASE_API_KEY<span class="token punctuation">,</span>
  authDomain<span class="token punctuation">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span>NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN<span class="token punctuation">,</span>
  projectId<span class="token punctuation">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span>NEXT_PUBLIC_FIREBASE_PROJECT_ID<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">getApps</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length <span class="token operator">?</span> <span class="token function">getApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token function">initializeApp</span><span class="token punctuation">(</span>firebaseConfig<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> auth <span class="token operator">=</span> <span class="token function">getAuth</span><span class="token punctuation">(</span>app<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> googleProvider <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">GoogleAuthProvider</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>This sets up a Firebase app instance using environment variables, with a guard to prevent duplicate initialization during Next.js hot reloads. It then exports the Firebase Authentication instance and a Google sign-in provider, both ready to be used anywhere in the app.</p><p>We also need to initialize the Firebase Admin SDK. Create a <code>src/lib/firebase-admin.ts</code> file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> admin <span class="token keyword">from</span> <span class="token string">"firebase-admin"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> fs <span class="token keyword">from</span> <span class="token string">"fs"</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>admin<span class="token punctuation">.</span>apps<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> serviceAccountPath <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span>FIREBASE_SERVICE_ACCOUNT <span class="token keyword">as</span> <span class="token keyword">string</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> serviceAccount <span class="token operator">=</span> JSON<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>
    fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>serviceAccountPath<span class="token punctuation">,</span> <span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  admin<span class="token punctuation">.</span><span class="token function">initializeApp</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    credential<span class="token punctuation">:</span> admin<span class="token punctuation">.</span>credential<span class="token punctuation">.</span><span class="token function">cert</span><span class="token punctuation">(</span>serviceAccount<span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> adminAuth <span class="token operator">=</span> admin<span class="token punctuation">.</span><span class="token function">auth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the code above, we initialized the Firebase Admin SDK, the server-side counterpart to the client-side Firebase setup. It reads the service account JSON file from the path specified in the <code>FIREBASE_SERVICE_ACCOUNT</code> environment variable, uses it to authenticate as a trusted admin and exports <code>adminAuth</code>, which will be used server-side to verify and decode user tokens sent from the client.</p><p>Next, create a <code>src/context/AuthContext.tsx</code> file and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token string">"use client"</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span>
  createContext<span class="token punctuation">,</span>
  useContext<span class="token punctuation">,</span>
  useEffect<span class="token punctuation">,</span>
  useState<span class="token punctuation">,</span>
  ReactNode<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> onAuthStateChanged<span class="token punctuation">,</span> User <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"firebase/auth"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> auth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/firebase"</span><span class="token punctuation">;</span>

<span class="token keyword">interface</span> <span class="token class-name">AuthContextValue</span> <span class="token punctuation">{</span>
  user<span class="token punctuation">:</span> User <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  loading<span class="token punctuation">:</span> boolean<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> AuthContext <span class="token operator">=</span> createContext<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>AuthContextValue</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  user<span class="token punctuation">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
  loading<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">AuthProvider</span><span class="token punctuation">(</span><span class="token punctuation">{</span> children <span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> children<span class="token punctuation">:</span> ReactNode <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>user<span class="token punctuation">,</span> setUser<span class="token punctuation">]</span> <span class="token operator">=</span> useState<span class="token operator">&lt;</span>User <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> unsubscribe <span class="token operator">=</span> <span class="token function">onAuthStateChanged</span><span class="token punctuation">(</span>auth<span class="token punctuation">,</span> <span class="token punctuation">(</span>firebaseUser<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token function">setUser</span><span class="token punctuation">(</span>firebaseUser<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">unsubscribe</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>AuthContext.Provider</span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> user<span class="token punctuation">,</span> loading <span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">{</span>children<span class="token punctuation">}</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>AuthContext.Provider</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">useAuth</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">useContext</span><span class="token punctuation">(</span>AuthContext<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>This file creates a React context that tracks the currently signed-in Firebase user across the app, exposing a user object and a loading state. The <code>useAuth</code> hook is then exported to allow access to the context values from any component.</p><p>Open the <code>src/app/layout.tsx</code> file and wrap the application with the context provider, <code>AuthProvider</code>, as shown below:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> type <span class="token punctuation">{</span> Metadata <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Geist<span class="token punctuation">,</span> Geist_Mono <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/font/google"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token string">"./globals.css"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> AuthProvider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/context/AuthContext"</span><span class="token punctuation">;</span>

<span class="token comment">//...</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">RootLayout</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  children<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">:</span> Readonly<span class="token operator">&lt;</span><span class="token punctuation">{</span>
  children<span class="token punctuation">:</span> React<span class="token punctuation">.</span>ReactNode<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>html
      lang<span class="token operator">=</span><span class="token string">"en"</span>
      className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>geistSans<span class="token punctuation">.</span>variable<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>geistMono<span class="token punctuation">.</span>variable<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> h-full antialiased`</span></span><span class="token punctuation">}</span>
    <span class="token operator">&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>min-h-full flex flex-col<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>AuthProvider</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>children<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>AuthProvider</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Now, let&rsquo;s create a simple login page that will be used to test the Firebase authentication in the browser.</p><p>Create a <code>src/app/login/page.tsx</code> file and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token string">"use client"</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/navigation"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> signInWithPopup <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"firebase/auth"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> auth<span class="token punctuation">,</span> googleProvider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/firebase"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">LoginPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>error<span class="token punctuation">,</span> setError<span class="token punctuation">]</span> <span class="token operator">=</span> useState<span class="token operator">&lt;</span>string <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> handleSignIn <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
      <span class="token keyword">await</span> <span class="token function">signInWithPopup</span><span class="token punctuation">(</span>auth<span class="token punctuation">,</span> googleProvider<span class="token punctuation">)</span><span class="token punctuation">;</span>
      router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">err</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">setError</span><span class="token punctuation">(</span><span class="token string">"Sign-in failed. Please try again."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex min-h-screen flex-col items-center justify-center gap-6 p-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-2xl font-bold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Weather Agent<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-gray-500<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Sign <span class="token keyword">in</span> to <span class="token keyword">continue</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">{</span>error <span class="token operator">&amp;&amp;</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm text-red-500<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>error<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
        <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleSignIn<span class="token punctuation">}</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-blue-600 text-white px-6 py-2 rounded<span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span>
        Sign <span class="token keyword">in</span> <span class="token keyword">with</span> Google
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>This renders a &ldquo;<strong>Sign in with Google</strong>&rdquo; button that triggers a Firebase Google pop-up sign-in. On success, the user is redirected to the homepage; on failure, an error message is displayed.</p><p>Now, let&rsquo;s protect our chat page and also attach the token. Open the <code>src/app/page.tsx</code> file and update it as shown below:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token string">"use client"</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect<span class="token punctuation">,</span> useRef <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/navigation"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> User <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"firebase/auth"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> signOut <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"firebase/auth"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> auth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/firebase"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useAuth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/context/AuthContext"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Home</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> user<span class="token punctuation">,</span> loading <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useAuth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> userRef <span class="token operator">=</span> useRef<span class="token operator">&lt;</span>User <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token punctuation">[</span>message<span class="token punctuation">,</span> setMessage<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>response<span class="token punctuation">,</span> setResponse<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>fetching<span class="token punctuation">,</span> setFetching<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    userRef<span class="token punctuation">.</span>current <span class="token operator">=</span> user<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>user<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>loading <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>user<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/login"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>user<span class="token punctuation">,</span> loading<span class="token punctuation">,</span> router<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> handleSubmit <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>message<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token operator">!</span>userRef<span class="token punctuation">.</span>current<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token function">setFetching</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setResponse</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> token <span class="token operator">=</span> <span class="token keyword">await</span> userRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">getIdToken</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"/api/chat"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
      method<span class="token punctuation">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
      headers<span class="token punctuation">:</span> <span class="token punctuation">{</span>
        <span class="token string">"Content-Type"</span><span class="token punctuation">:</span> <span class="token string">"application/json"</span><span class="token punctuation">,</span>
        Authorization<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`Bearer </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      body<span class="token punctuation">:</span> JSON<span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setResponse</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>response <span class="token operator">?</span><span class="token operator">?</span> data<span class="token punctuation">.</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setFetching</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> handleSignOut <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> <span class="token function">signOut</span><span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">;</span>
    router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/login"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>loading <span class="token operator">||</span> <span class="token operator">!</span>user<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex min-h-screen flex-col items-center justify-center p-8 gap-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-full max-w-lg flex justify-between items-center<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-2xl font-bold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Weather Agent<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex items-center gap-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm text-gray-500<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>user<span class="token punctuation">.</span>email<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
            <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleSignOut<span class="token punctuation">}</span></span>
            <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm text-red-500 hover:underline<span class="token punctuation">"</span></span>
          <span class="token punctuation">&gt;</span></span>
            Sign out
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>textarea</span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-full max-w-lg border rounded p-3 text-sm<span class="token punctuation">"</span></span>
        <span class="token attr-name">rows</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">3</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Ask about the weather anywhere...<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>message<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setMessage</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
        <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span></span>
        <span class="token attr-name">disabled</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>fetching<span class="token punctuation">}</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-blue-600 text-white px-6 py-2 rounded disabled:opacity-50<span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">{</span>fetching <span class="token operator">?</span> <span class="token string">"Thinking..."</span> <span class="token punctuation">:</span> <span class="token string">"Send"</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">{</span>response <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-full max-w-lg border rounded p-4 bg-gray-50 text-sm<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token punctuation">{</span>response<span class="token punctuation">}</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">}</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>The code above redirects a user if not authenticated. On the other hand, if authenticated, it presents the user with a <code>textarea</code> to send messages to the weather agent.</p><p>Before each request, it fetches a fresh Firebase ID token and attaches it to the Authorization header when calling the <code>/api/chat</code> endpoint. It also displays the agent&rsquo;s response and provides a sign-out button.</p><p>That&rsquo;s it for the client side. Now let&rsquo;s update the API route to verify the token. Open the <code>src/app/api/chat/route.ts</code> file and update the code as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> mastra <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/mastra"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> NextResponse <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/server"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> adminAuth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/firebase-admin"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">POST</span><span class="token punctuation">(</span>req<span class="token punctuation">:</span> Request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> authHeader <span class="token operator">=</span> req<span class="token punctuation">.</span>headers<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">"Authorization"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>authHeader <span class="token operator">||</span> <span class="token operator">!</span>authHeader<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">"Bearer "</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> error<span class="token punctuation">:</span> <span class="token string">"Unauthorized"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token number">401</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> idToken <span class="token operator">=</span> authHeader<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">"Bearer "</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> adminAuth<span class="token punctuation">.</span><span class="token function">verifyIdToken</span><span class="token punctuation">(</span>idToken<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span>
      <span class="token punctuation">{</span> error<span class="token punctuation">:</span> <span class="token string">"Invalid or expired token"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token number">401</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> <span class="token punctuation">{</span> message <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> req<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>message<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> error<span class="token punctuation">:</span> <span class="token string">"Message is required"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token number">400</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> agent <span class="token operator">=</span> mastra<span class="token punctuation">.</span><span class="token function">getAgent</span><span class="token punctuation">(</span><span class="token string">"weatherAgent"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> agent<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span> role<span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span> content<span class="token punctuation">:</span> message <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> response<span class="token punctuation">:</span> result<span class="token punctuation">.</span>text <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, instead of just receiving messages from the client side and generating responses based on that, we now include an authentication verification layer.</p><p>First, it validates the Authorization header, extracting and verifying the Firebase ID token using the Admin SDK. It rejects any request that is unauthenticated or carries an invalid token. If verification passes, it forwards the user&rsquo;s message to the Mastra weather agent and returns the agent&rsquo;s response.</p><p>For the final piece, which is adding the authentication guard to our Mastra instance, update the <code>src/mastra/index.ts</code> file as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Mastra <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@mastra/core/mastra"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> PinoLogger <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@mastra/loggers"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> LibSQLStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@mastra/libsql"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  Observability<span class="token punctuation">,</span>
  DefaultExporter<span class="token punctuation">,</span>
  CloudExporter<span class="token punctuation">,</span>
  SensitiveDataFilter<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@mastra/observability"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> weatherWorkflow <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./workflows/weather-workflow"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> weatherAgent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./agents/weather-agent"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> MastraAuthFirebase <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@mastra/auth-firebase"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> mastra <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Mastra</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  workflows<span class="token punctuation">:</span> <span class="token punctuation">{</span> weatherWorkflow <span class="token punctuation">}</span><span class="token punctuation">,</span>
  agents<span class="token punctuation">:</span> <span class="token punctuation">{</span> weatherAgent <span class="token punctuation">}</span><span class="token punctuation">,</span>
  storage<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">LibSQLStore</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span> <span class="token string">"mastra-storage"</span><span class="token punctuation">,</span>
    url<span class="token punctuation">:</span> <span class="token string">"file:./mastra.db"</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  server<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    auth<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">MastraAuthFirebase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  logger<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">PinoLogger</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    name<span class="token punctuation">:</span> <span class="token string">"Mastra"</span><span class="token punctuation">,</span>
    level<span class="token punctuation">:</span> <span class="token string">"info"</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  observability<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Observability</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    configs<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
        serviceName<span class="token punctuation">:</span> <span class="token string">"mastra"</span><span class="token punctuation">,</span>
        exporters<span class="token punctuation">:</span> <span class="token punctuation">[</span>
          <span class="token keyword">new</span> <span class="token class-name">DefaultExporter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token keyword">new</span> <span class="token class-name">CloudExporter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
        spanOutputProcessors<span class="token punctuation">:</span> <span class="token punctuation">[</span>
          <span class="token keyword">new</span> <span class="token class-name">SensitiveDataFilter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>For now, pay close attention only to this part:</p><pre class=" language-ts"><code class="prism  language-ts">server<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    auth<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">MastraAuthFirebase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
</code></pre><p>By passing an instance of the <code>MastraAuthFirebase</code> class to the auth option in the Mastra server config, Mastra will automatically intercept every incoming request to the agent and validate the Firebase ID token, thereby restricting access if no token is provided or if an invalid token is provided.</p><p>It is important to note that <code>MastraAuthFirebase</code> will automatically read the <code>FIREBASE_SERVICE_ACCOUNT</code> and <code>FIRESTORE_DATABASE_ID</code> environment variables, so no additional configuration is required other than verifying those values are set in the <code>.env</code> file.</p><p>Now you can test the application in your browser to see the authentication in action.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/firebase-agent-authentication.png?sfvrsn=c487a53f_2" title="Firebase agent authentication" alt="Firebase agent authentication" /></p><h2 id="implementing-authorization">Implementing Authorization</h2><p>With authentication done, our agent is no longer publicly accessible so only signed-in users can access it. In this section, we&rsquo;ll add an extra layer of control, which involves checking whether an authenticated user actually has permission to use the agent.</p><p>For this, we need somewhere to store user roles. Firestore is the best fit for this, since it is already part of the Firebase ecosystem.</p><p>In the sidebar of the Firebase dashboard, go to <strong>Databases and Storage</strong> &rarr; <strong>Firestore</strong> and click &ldquo;Create Database.&rdquo; Next, pick a region and select &ldquo;Start in test mode.&rdquo;</p><p>After successfully creating it, open the <code>.env</code> file and add the database ID as shown below:</p><pre class=" language-js"><code class="prism  language-js"><span class="token comment">//...previous environment variables</span>

FIRESTORE_DATABASE_ID<span class="token operator">=</span><span class="token punctuation">(</span><span class="token keyword">default</span><span class="token punctuation">)</span>
</code></pre><p>In the snippet above, <code>(default)</code> is the ID Firestore assigns to the first database it creates for a project.</p><p>Now, open the <code>src/lib/firebase-admin.ts</code> file to update the Firestore admin to export Firestore:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> admin <span class="token keyword">from</span> <span class="token string">"firebase-admin"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> fs <span class="token keyword">from</span> <span class="token string">"fs"</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>admin<span class="token punctuation">.</span>apps<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> serviceAccountPath <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span>FIREBASE_SERVICE_ACCOUNT <span class="token keyword">as</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> serviceAccount <span class="token operator">=</span> JSON<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>
    fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>serviceAccountPath<span class="token punctuation">,</span> <span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  admin<span class="token punctuation">.</span><span class="token function">initializeApp</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    credential<span class="token punctuation">:</span> admin<span class="token punctuation">.</span>credential<span class="token punctuation">.</span><span class="token function">cert</span><span class="token punctuation">(</span>serviceAccount<span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> adminAuth <span class="token operator">=</span> admin<span class="token punctuation">.</span><span class="token function">auth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> adminFirestore <span class="token operator">=</span> admin<span class="token punctuation">.</span><span class="token function">firestore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Here, <code>admin.firestore()</code> provides a Firestore client that uses the service account credentials. Instead of writing the role-checking logic directly inside the API route, let&rsquo;s create a separate file for that. Create a <code>src/lib/authorization.ts</code> file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> adminFirestore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./firebase-admin"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">type</span> UserRole <span class="token operator">=</span> <span class="token string">"admin"</span> <span class="token operator">|</span> <span class="token string">"user"</span> <span class="token operator">|</span> <span class="token string">"blocked"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> ALLOWED_ROLES<span class="token punctuation">:</span> UserRole<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"admin"</span><span class="token punctuation">,</span> <span class="token string">"user"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getUserRole</span><span class="token punctuation">(</span>uid<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span><span class="token punctuation">:</span> Promise<span class="token operator">&lt;</span>UserRole <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> doc <span class="token operator">=</span> <span class="token keyword">await</span> adminFirestore<span class="token punctuation">.</span><span class="token function">collection</span><span class="token punctuation">(</span><span class="token string">"users"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">doc</span><span class="token punctuation">(</span>uid<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>doc<span class="token punctuation">.</span>exists<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> data <span class="token operator">=</span> doc<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token punctuation">{</span> role<span class="token punctuation">:</span> UserRole <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> data<span class="token punctuation">.</span>role <span class="token operator">?</span><span class="token operator">?</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">isUserAuthorized</span><span class="token punctuation">(</span>uid<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span><span class="token punctuation">:</span> Promise<span class="token operator">&lt;</span><span class="token keyword">boolean</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> role <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getUserRole</span><span class="token punctuation">(</span>uid<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>role<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">false</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> ALLOWED_ROLES<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>role<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, <code>getUserRole</code> takes a Firebase UID, looks up the corresponding document in the users Firestore collection, and returns the role stored in it. If no document exists for that UID, it returns <code>null</code>, meaning that the user has never been granted access.</p><p>Also, <code>isUserAuthorized</code> calls <code>getUserRole</code> and checks whether the result is in the <code>ALLOWED_ROLES</code> array. Only &ldquo;admin&rdquo; and &ldquo;user&rdquo; pass this check. A &ldquo;blocked&rdquo; role or a missing document both return false.</p><p>Next, let&rsquo;s add the authorization check to our API route. Open the <code>src/app/api/chat/route.ts</code> file and update the code as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> mastra <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/mastra"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> NextResponse <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/server"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> adminAuth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/firebase-admin"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> isUserAuthorized <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/authorization"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">POST</span><span class="token punctuation">(</span>req<span class="token punctuation">:</span> Request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> authHeader <span class="token operator">=</span> req<span class="token punctuation">.</span>headers<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">"Authorization"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>authHeader <span class="token operator">||</span> <span class="token operator">!</span>authHeader<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">"Bearer "</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> error<span class="token punctuation">:</span> <span class="token string">"Unauthorized"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token number">401</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> idToken <span class="token operator">=</span> authHeader<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">"Bearer "</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> decodedToken<span class="token punctuation">;</span>

  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    decodedToken <span class="token operator">=</span> <span class="token keyword">await</span> adminAuth<span class="token punctuation">.</span><span class="token function">verifyIdToken</span><span class="token punctuation">(</span>idToken<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span>
      <span class="token punctuation">{</span> error<span class="token punctuation">:</span> <span class="token string">"Invalid or expired token"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token number">401</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> authorized <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">isUserAuthorized</span><span class="token punctuation">(</span>decodedToken<span class="token punctuation">.</span>uid<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>authorized<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span>
      <span class="token punctuation">{</span> error<span class="token punctuation">:</span> <span class="token string">"You do not have access to this agent."</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token number">403</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> <span class="token punctuation">{</span> message <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> req<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>message<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> error<span class="token punctuation">:</span> <span class="token string">"Message is required"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token number">400</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> agent <span class="token operator">=</span> mastra<span class="token punctuation">.</span><span class="token function">getAgent</span><span class="token punctuation">(</span><span class="token string">"weatherAgent"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> agent<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span> role<span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span> content<span class="token punctuation">:</span> message <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> NextResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> response<span class="token punctuation">:</span> result<span class="token punctuation">.</span>text <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>We updated the code to follow a sequential flow. First, we verify the token (authentication), then checking the role (authorization). If either check fails, an error is returned.</p><p>Notice how the message is only read after both checks pass. There is no reason to retrieve the message if the user is not authenticated or not authorized.</p><p>Now, let&rsquo;s update our Mastra server instance. We want to inform it about our role system as well, so that even direct calls to Mastra&rsquo;s server go through the same authorization logic.</p><p>Open the <code>src/mastra/index.ts</code> file and update it as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Mastra <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@mastra/core/mastra"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> PinoLogger <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@mastra/loggers"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> LibSQLStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@mastra/libsql"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  Observability<span class="token punctuation">,</span>
  DefaultExporter<span class="token punctuation">,</span>
  CloudExporter<span class="token punctuation">,</span>
  SensitiveDataFilter<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@mastra/observability"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> weatherWorkflow <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./workflows/weather-workflow"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> weatherAgent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./agents/weather-agent"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> MastraAuthFirebase <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@mastra/auth-firebase"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> isUserAuthorized <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/authorization"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> mastra <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Mastra</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  workflows<span class="token punctuation">:</span> <span class="token punctuation">{</span> weatherWorkflow <span class="token punctuation">}</span><span class="token punctuation">,</span>
  agents<span class="token punctuation">:</span> <span class="token punctuation">{</span> weatherAgent <span class="token punctuation">}</span><span class="token punctuation">,</span>
  storage<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">LibSQLStore</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span> <span class="token string">"mastra-storage"</span><span class="token punctuation">,</span>
    url<span class="token punctuation">:</span> <span class="token string">"file:./mastra.db"</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  server<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    auth<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">MastraAuthFirebase</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      authorizeUser<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>user<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token function">isUserAuthorized</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  logger<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">PinoLogger</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    name<span class="token punctuation">:</span> <span class="token string">"Mastra"</span><span class="token punctuation">,</span>
    level<span class="token punctuation">:</span> <span class="token string">"info"</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  observability<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Observability</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    configs<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
        serviceName<span class="token punctuation">:</span> <span class="token string">"mastra"</span><span class="token punctuation">,</span>
        exporters<span class="token punctuation">:</span> <span class="token punctuation">[</span>
          <span class="token keyword">new</span> <span class="token class-name">DefaultExporter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token keyword">new</span> <span class="token class-name">CloudExporter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
        spanOutputProcessors<span class="token punctuation">:</span> <span class="token punctuation">[</span>
          <span class="token keyword">new</span> <span class="token class-name">SensitiveDataFilter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Let&rsquo;s pay attention to this block of code:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> mastra <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Mastra</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token operator">...</span>
  server<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    auth<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">MastraAuthFirebase</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      authorizeUser<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>user<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token function">isUserAuthorized</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>uid<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">///</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The <code>authorizeUser</code> function receives the decoded Firebase token after verification. Then <code>user.uid</code> is passed to the same <code>isUserAuthorized</code> function we used earlier in the API route. This keeps the role logic in one place and enforces it consistently across both entry points.</p><p>Let&rsquo;s update the chat page to acknowledge authorization. Open the <code>src/app/page.tsx</code> file and update the code as shown below:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token string">"use client"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect<span class="token punctuation">,</span> useRef <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/navigation"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> User <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"firebase/auth"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> signOut <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"firebase/auth"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> auth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/lib/firebase"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useAuth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@/context/AuthContext"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Home</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> user<span class="token punctuation">,</span> loading <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useAuth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> userRef <span class="token operator">=</span> useRef<span class="token operator">&lt;</span>User <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token punctuation">[</span>message<span class="token punctuation">,</span> setMessage<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>response<span class="token punctuation">,</span> setResponse<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>fetching<span class="token punctuation">,</span> setFetching<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>forbidden<span class="token punctuation">,</span> setForbidden<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    userRef<span class="token punctuation">.</span>current <span class="token operator">=</span> user<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>user<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>loading <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>user<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/login"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>user<span class="token punctuation">,</span> loading<span class="token punctuation">,</span> router<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> handleSubmit <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>message<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token operator">!</span>userRef<span class="token punctuation">.</span>current<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token function">setFetching</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setResponse</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> token <span class="token operator">=</span> <span class="token keyword">await</span> userRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">getIdToken</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"/api/chat"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
      method<span class="token punctuation">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
      headers<span class="token punctuation">:</span> <span class="token punctuation">{</span>
        <span class="token string">"Content-Type"</span><span class="token punctuation">:</span> <span class="token string">"application/json"</span><span class="token punctuation">,</span>
        Authorization<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`Bearer </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      body<span class="token punctuation">:</span> JSON<span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token number">403</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">setForbidden</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">setFetching</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setResponse</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>response <span class="token operator">?</span><span class="token operator">?</span> data<span class="token punctuation">.</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setFetching</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> handleSignOut <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> <span class="token function">signOut</span><span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">;</span>
    router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/login"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>loading <span class="token operator">||</span> <span class="token operator">!</span>user<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex min-h-screen flex-col items-center justify-center p-8 gap-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-full max-w-lg flex justify-between items-center<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-2xl font-bold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Weather Agent<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex items-center gap-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm text-gray-500<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>user<span class="token punctuation">.</span>email<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
            <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleSignOut<span class="token punctuation">}</span></span>
            <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm text-red-500 hover:underline<span class="token punctuation">"</span></span>
          <span class="token punctuation">&gt;</span></span>
            Sign out
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

      <span class="token punctuation">{</span>forbidden <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-full max-w-lg border border-red-300 rounded p-4 bg-red-50 text-sm text-red-700<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          You <span class="token keyword">do</span> not have access to <span class="token keyword">this</span> agent<span class="token punctuation">.</span> Please contact the
          administrator<span class="token punctuation">.</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">}</span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>textarea</span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-full max-w-lg border rounded p-3 text-sm<span class="token punctuation">"</span></span>
        <span class="token attr-name">rows</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token number">3</span><span class="token punctuation">}</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Ask about the weather anywhere...<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>message<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setMessage</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
        <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleSubmit<span class="token punctuation">}</span></span>
        <span class="token attr-name">disabled</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>fetching<span class="token punctuation">}</span></span>
        <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-blue-600 text-white px-6 py-2 rounded disabled:opacity-50<span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">{</span>fetching <span class="token operator">?</span> <span class="token string">"Thinking..."</span> <span class="token punctuation">:</span> <span class="token string">"Send"</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">{</span>response <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-full max-w-lg border rounded p-4 bg-gray-50 text-sm<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token punctuation">{</span>response<span class="token punctuation">}</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">}</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Here, we added a new forbidden state that is set to <code>true</code> when the user is unauthorized. In that case, a message is rendered on the screen. The user then understands what happened and what to do next (contact whoever manages access).</p><p>To test this, in the Firestore database we created earlier, create a collection called <code>users</code>. Follow the steps below for each user you want to grant access:</p><ul><li>Click &ldquo;Add document.&rdquo;</li><li>Set the Document ID to the user&rsquo;s Firebase UID (you&rsquo;ll have to copy this from Authentication &rarr; Users in the Firebase dashboard).</li><li>Add two fields: email and role. Email should be of type <code>string</code> with a value of the email you want to test with. Role should also be of type <code>string</code>, and its value should be either &ldquo;user&rdquo; or &ldquo;admin,&rdquo; or &ldquo;blocked&rdquo; if you want to deny a user access.</li></ul><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/role-definition-unauthorized.png?sfvrsn=540f6e8f_2" title="Firebase user role definition - unauthorized" alt="Firebase user role definition - unauthorized" /></p><p>For this demo, we are manually adding users to Firestore to keep things simple. In a real application, you would automate this by creating the user&rsquo;s Firestore document programmatically right after their first sign-in.</p><p>Go to the <strong>Rules</strong> tab in Firestore and update the default rules as shown below:</p><pre class=" language-js"><code class="prism  language-js">rules_version <span class="token operator">=</span> <span class="token string">'2'</span><span class="token punctuation">;</span>
service cloud<span class="token punctuation">.</span>firestore <span class="token punctuation">{</span>
  match <span class="token operator">/</span>databases<span class="token operator">/</span><span class="token punctuation">{</span>database<span class="token punctuation">}</span><span class="token operator">/</span>documents <span class="token punctuation">{</span>
    
    match <span class="token operator">/</span><span class="token punctuation">{</span>document<span class="token operator">=</span><span class="token operator">**</span><span class="token punctuation">}</span> <span class="token punctuation">{</span>
      allow read<span class="token punctuation">,</span> write<span class="token punctuation">:</span> <span class="token keyword">if</span> request<span class="token punctuation">.</span>time <span class="token operator">&lt;</span> timestamp<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token number">2026</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">23</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
    match <span class="token operator">/</span>users<span class="token operator">/</span><span class="token punctuation">{</span>uid<span class="token punctuation">}</span> <span class="token punctuation">{</span>
      allow read<span class="token punctuation">,</span> write<span class="token punctuation">:</span> <span class="token keyword">if</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>This prevents any browser code from reading role data directly. The server (Admin SDK) bypasses these rules entirely, so it still works fine.</p><p>Now, you can test the application in your browser. The agent now restricts access to users with the &ldquo;blocked&rdquo; role.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/unauthorized-user.png?sfvrsn=e87e25d_2" title="Firebase unauthorized user" alt="Firebase unauthorized user" /></p><p>Change the role to &ldquo;admin&rdquo; or &ldquo;user.&rdquo;</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/firebase-role-definition-authorized.png?sfvrsn=7078dee0_2" title="Firebase role definition - authorized" alt="Firebase role definition - authorized" /></p><p>The user can now get responses to messages sent.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/firebase-authorized-user.png?sfvrsn=39f45b2_2" title="Firebase authorized user" alt="Firebase authorized user" /></p><h2 id="conclusion">Conclusion</h2><p>Agent authentication and authorization are key security mechanisms that cannot be overlooked. Authentication confirms who the user accessing an agent is, while authorization determines whether that user should be granted access.</p><p>The MastraAuthFirebase class makes the setup straightforward and allows us to add these security layers to our agent&rsquo;s server easily.</p><p>In this article, we built a simple Next.js project that implements authentication and authorization across the frontend, the Next.js API, and the agent&rsquo;s server. We covered the basics here, but you can explore the official <a target="_blank" href="https://mastra.ai/docs">Mastra documentation</a> to build on what we covered.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">How a 6-Person Team Shipped an AI-First Platform with KendoReact</h4></div><div class="col-8"><p class="u-fs16 u-mb0">For teams building AI-driven applications with complex workflows, treating the UI layer as infrastructure can dramatically reduce friction as the product evolves. <a target="_blank" href="https://www.telerik.com/blogs/how-a-6-person-team-shipped-an-ai-first-platform-with-kendoreact">For Icanpreneur, KendoReact became that foundation.</a></p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17379534.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:a18a06d4-7545-4d98-b443-2c8bf61c38c4</id>
    <title type="text">5 Mistakes Teams Make When Scaling  .NET Applications</title>
    <summary type="text">Avoid these common infrastructure-related mistakes when you’re ready to scale your .NET app to keep your performance at scale too.</summary>
    <published>2026-07-10T16:44:45Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Brien Posey </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17376190/5-mistakes-teams-make-when-scaling-net-applications"/>
    <content type="text"><![CDATA[<p><span class="featured">Avoid these common infrastructure-related mistakes when you&rsquo;re ready to scale your .NET app to keep your performance at scale too.</span></p><p>IT teams often assume that scaling a .NET application means moving it to a larger virtual machine or containerizing the application. While such actions do have their place, performance problems are often tied to infrastructure design rather than the application itself.</p><p>This article discusses some of the most common infrastructure-related mistakes that are often made when scaling a .NET application.</p><h2 id="adding-instances-without-thinking-about-traffic-distribution">1. Adding Instances Without Thinking About Traffic Distribution</h2><p>Application scaling very often involves adding additional nodes to handle the increased demand. However, it is a mistake to add nodes without considering how requests will reach those nodes. Oftentimes organizations will use round-robin load balancing to evenly distribute inbound requests across the available nodes. However, load balancing can break down when session affinity comes into play.</p><p>Session affinity occurs as a result of session data being stored on a specific server. This in turn causes all of a user&rsquo;s requests to be sent to that same server, because that&rsquo;s where the user&rsquo;s session lives. This isn&rsquo;t necessarily a problem by itself, but session affinity can become problematic under the right conditions, especially when there is a mixture of active and inactive users.</p><p>In such situations, a particular instance may become overloaded, even if plenty of capacity exists on other instances, simply because the session is bound to that instance. Additionally, if that instance were to fail, then the users on that instance lose their session.</p><p>A better approach is to design services to be stateless and to store session data within shared storage rather than placing it in an instance&rsquo;s memory. This allows the load balancer to freely distribute requests.</p><h2 id="assuming-that-all-requests-look-alike">2. Assuming That All Requests Look Alike</h2><p>Basic load distribution strategies, such as round robin, assume that every instance can deliver the same level of performance and that every request has the same impact. In reality though, these assumptions are na&iuml;ve.</p><p>Some requests, for example, trigger longer running operations, call external services or make more complex database queries. As such, some requests will inevitably be completed more quickly than others. This can result in some nodes being bogged down while others remain nearly idle.</p><p>The best way to avoid this type of problem is to avoid blindly distributing traffic across nodes. Instead, consider each node&rsquo;s health when making routing decisions. As an example, if a node were experiencing excessive latency or had a significant queue depth, then it would be better to route inbound requests to a node that is under less of a load rather than assigning the request to the struggling node just because it is that node&rsquo;s turn.</p><h2 id="not-having-a-load-shedding-strategy">3. Not Having a Load-Shedding Strategy</h2><p>Although it may seem counterintuitive, load shedding can sometimes be the most appropriate course of action. For those who might not be familiar with the term, load shedding refers to the practice of intentionally rejecting certain requests as a way of helping the system to stay healthy.</p><p>To use an analogy from everyday life, consider what might happen if a restaurant kept seating additional guests in spite of the kitchen and the waitstaff being completely overwhelmed. In such a situation, everyone would receive poor service. Conversely, if the restaurant were to pause and not seat anyone else until the staff had a chance to catch up, then it would result in a better overall experience for everyone.</p><p>Load shedding works similarly. When a system becomes overwhelmed with more requests than the nodes can handle, then the load balancer intentionally fails some requests so that those requests that do make it through can still be serviced normally.</p><h2 id="lack-of-visibility">4. Lack of Visibility</h2><p>This one seems so simple (and it is), yet it is so important. Organizations often make the mistake of just assuming that load balancing is working as intended without doing anything to verify their assumptions. The problem is that if an organization cannot see how requests are being routed, then scaling an application becomes guesswork.</p><p>Without proper visibility, you can&rsquo;t tell whether traffic is being evenly distributed, if there are nodes that are constantly struggling or which instances are handling slow requests. It becomes easy to misdiagnose bottlenecks and blame the application for poor performance when routing is the real problem (or vice versa).</p><p>Ideally, an organization should be able to collect per-instance metrics from its nodes including CPU and memory usage and the request count. There should also be a way to trace requests as they flow across services and there should be a way to track load distribution metrics to see how the individual nodes are being leveraged.</p><h2 id="treating-load-balancing-as-an-afterthought">5. Treating Load Balancing as an Afterthought</h2><p>One of the single biggest mistakes that is often made when scaling an application is treating load balancing as an afterthought. Typically, an application is deployed and works fine. Eventually though, demand increases and the application begins to struggle. IT distributes the application across several nodes and places a basic load balancer in front of those nodes. In these types of situations, load balancers often use default settings because, &ldquo;round robin is good enough for not&rdquo; or &ldquo;the cloud provider&rsquo;s defaults should be fine.&rdquo;</p><p>The end result is that while the application has indeed been scaled, there is a good chance that some of the original problems still exist. The added infrastructure now makes those problems more difficult to diagnose.</p><p>True load balancing is not about spreading traffic evenly. It&rsquo;s about making informed decisions as to where each inbound request should be routed. This informed decision making means using application aware routing to base routing decisions on application behavior, not just routing rules. It also means taking instance health and readiness into account and continually adjusting routing decisions based on latency, errors and available capacity.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Using AI to Build a Blazor App 1: Start With the Problem
</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Many AI-assisted projects fail before a line of code is written because the idea was never properly defined. <a target="_blank" href="https://www.telerik.com https://www.telerik.com/blogs/using-ai-build-blazor-app-1-start-problem">Here&rsquo;s how to use an LLM to interrogate your own thinking until a vague premise becomes something you can actually build.</a></p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17376190.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:8720cf41-2dac-4533-a2fe-cf1af00e248f</id>
    <title type="text">Using AI to Build a Blazor App 1: Start With the Problem</title>
    <summary type="text">Many AI-assisted projects fail before a line of code is written because the idea was never properly defined. Here’s how to use an LLM to interrogate your own thinking until a vague premise becomes something you can actually build.</summary>
    <published>2026-07-07T15:05:27Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Jon Hilton </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17374525/using-ai-build-blazor-app-1-start-problem"/>
    <content type="text"><![CDATA[<p><span class="featured">Many AI-assisted projects fail before a line of code is written because the idea was never properly defined. Here&rsquo;s how to use an LLM to interrogate your own thinking until a vague premise becomes something you can actually build.</span></p><p>How do you go from idea to working software? That&rsquo;s the challenge we face as software developers.</p><p>While AI <strong>feels</strong> like it&rsquo;s changed everything, it hasn&rsquo;t changed that fundamental problem.</p><p>It&rsquo;s not a question of how quickly AI can write code (answer: very quickly), but rather how soon can we find out if our assumptions are correct and if we&rsquo;re building the right thing to move the needle.</p><p>Do we even know what needle we&rsquo;re trying to move in the first place?</p><p>In this short series, we&rsquo;ll explore how we can use AI to build the right things, to solve the most urgent problems, without shipping substandard code.</p><ul><li>We&rsquo;ll start with a vague premise and see if AI can help us sharpen our understanding of what we&rsquo;re building (and why).</li><li>Then we&rsquo;ll move on to working with AI to carve out the headline feature we want to build first.</li><li>We&rsquo;ll remove ambiguity (and reach a shared understanding of what we&rsquo;re building) using prototypes and tracer bullets.</li><li>Then we&rsquo;ll establish the architecture of what we&rsquo;re building (including key technology choices), break the work down into smaller steps and build it.</li></ul><p>First, we need to get clear about what we&rsquo;re building.</p><h2 id="a-journey-of-a-thousand-miles-begins-with-a-single-step">A Journey of a Thousand Miles Begins with a Single Step</h2><p>If you&rsquo;ve been experimenting with AI, you already know the big AI trap. The temptation to just throw a vague prompt its way, cross your fingers and hope it magically builds the perfect web application (while you sleep).</p><p>In reality it&rsquo;s not that simple.</p><p>AI will happily run off and build whatever you ask it to, which is problematic if you ask it to build the wrong thing, start with fuzzy requirements or give it too much to do in one step.</p><p>So, the first task is the same as it&rsquo;s always been: get clear about the problem you&rsquo;re solving.</p><p>In this case, I started with a simple problem to solve. I have a goal of writing at least one article a week for my personal blog and also an email to my newsletter audience (based on the same blog post). In reality, that cadence is rarely once a week, and often drifts to once a month or, in the worst case, once &ldquo;every now and then.&rdquo;</p><p>So starting with that problem, I gave this prompt to GPT 5.5 (via the Codex GUI):</p><blockquote><p>I want to build a new web application using .NET 10 and Blazor. Please grill me on the idea, what it&rsquo;s for, key technology choices, and help me scope out a reasonable first version so we can get user feedback as soon as possible</p></blockquote><p>This did <strong>not</strong> go well.</p><p>GPT 5.5 responded with a giant wall of text and lots of questions. It started diving into implementation details about Blazor (which render mode to use, etc.) and essentially skipped the part where it finds out what I&rsquo;m trying to build before focusing on those implementation details.</p><p>I started over, and tried different variations of the same prompt.</p><p>First I got it to ask me one question at a time, which worked better, but I realized it was still jumping to technical details. I wanted to keep it focused on problems and ideal outcomes, not technical matters or even defining the feature details at this stage.</p><p>After a few iterations we arrived at this:</p><blockquote><p>I want to build a new web application using .NET 10 and Blazor.</p><p>Please grill me on the idea.</p><p>Ask me one question at a time, and include your brief recommendation for each question.</p><p>Dig into each answer until that thread is clear, then move on to the next question.</p><p>For notable decisions (anything fundamental, or where the reasoning for which can&rsquo;t be deduced from implementation), capture that decision as an ADR in a decisions folder.</p><p>Help me explore the problem space, and the core outcomes we want this application to achieve.</p><p>Do not scope features at this point, that will come next.</p></blockquote><p>This worked better.</p><p>Over the course of a 45-minute back-and-forth, we fleshed out the problem I was trying to solve, and the rough shape of any potential solution. I won&rsquo;t include the entire conversation here, but here are some highlights.</p><p>It asked:</p><blockquote><p>Where do ideas currently appear first: while at your computer, on your phone, in notes, in code/projects, from conversations, or somewhere else?</p></blockquote><p>The answer I gave included this phrase: &ldquo;Could be anywhere really.&rdquo;</p><p>GPT 5.5 wasn&rsquo;t having that.</p><blockquote><p>This one isn&rsquo;t quite a decision yet, because &ldquo;could be anywhere&rdquo; can lead to a lot of product surface.</p><p>Follow-up question:</p><p>For the first version, is it acceptable if mobile capture is only a lightweight inbox, with real writing/editing still expected to happen at a keyboard?</p></blockquote><p>In my experience, AI shines with this kind of process, digging into answers you give it and getting clear so you can make concrete decisions, not just hand-wavey &ldquo;ideas.&rdquo;</p><p>Some more questions it posed:</p><blockquote><p>What would make this application feel like a calm writing system rather than another obligation to maintain?</p></blockquote><blockquote><p>What is the smallest publishing rhythm that would still feel successful: exactly one post/email every week, or a sustainable average with occasional skips and catch-ups?</p></blockquote><blockquote><p>What would make you stop using this app, even if it technically worked?</p></blockquote><p>Notice how GPT 5.5 stayed on task here, exploring the problem and not getting into feature design, or technical choices.</p><p>Eventually we arrived at this summary:</p><blockquote><p>The core shape is now clear: a local-first, single-user Blazor/.NET app that helps you maintain a weekly blog-plus-newsletter rhythm, with the Astro repo as source of truth, a calm Markdown writing experience, lightweight AI assistance, and explicit publishing/Git steps.</p></blockquote><p>The main technical decision made was the one I started with (that we&rsquo;d be using Blazor to build it) and some high level thoughts around source of truth, and the existing systems (like my blog).</p><p>We also ended up with a number of architecture decision records (ADRs) captured in markdown documents. ADRs are typically used to capture technical decisions, but were also useful here for capturing the decisions we arrived at around the problem and solution itself.</p><p>Here&rsquo;s one example:</p><pre class=" language-markdown"><code class="prism  language-markdown"><span class="token title important"><span class="token punctuation">#</span> ADR 0028: Slug Generation</span>
Status
Accepted

<span class="token title important"><span class="token punctuation">##</span> Context</span>
Blog posts need a final URL slug. The slug should usually be short, readable, and aligned with the article's content or main takeaway.

Manual override is sometimes needed.

<span class="token title important"><span class="token punctuation">##</span> Decision</span>
The application should generate slugs automatically from the article title or main takeaway, while allowing the user to override them.

Slugs should be treated as stable after publication unless deliberately changed.

<span class="token title important"><span class="token punctuation">##</span> Consequences</span>
Slug generation should optimize for short, meaningful URLs rather than blindly mirroring the full title.
The user must retain control over the final slug.
Published slug changes should be treated as deliberate edits, not incidental metadata updates.
</code></pre><p>Whenever I work through an AI interview like this, I find I emerge with a much clearer picture of what I&rsquo;m building (and why). The LLM&rsquo;s questions force me to think and often surface angles I hadn&rsquo;t previously considered. In some cases I&rsquo;ve gone on to realize building a feature is actually unnecessary (a change to existing habits or processes would achieve the same result).</p><p>In this case, though, we&rsquo;re on the right track and have a clearly scoped brief for an editor to capture ideas and author content.</p><h2 id="make-it-work-for-you">Make It Work for You</h2><p>When you try to use AI to build something like this, you might feel like there should be some simple streamlined process you can work through. A clean process where you feed a feature idea in, AI gives you perfect code out and you ride off into the sunset.</p><p>Alas, software design is anything but streamlined, and no AI tool is going to take the chaos of defining and refining an idea and handle it in a nice straight line.</p><p>In this case, getting AI to grill you about the idea is one part of the design process, but there are others, which we&rsquo;ll come to shortly. We started high-level here because this was an embryonic idea and a greenfield application. But if you already had an app and were adding a feature, you might skip this step and jump straight into designing a specific feature/requirement.</p><h2 id="iterate-your-prompts">Iterate Your Prompts</h2><p>But what about the prompt itself? Did I happen upon some perfect, fully formed prompt that made AI work perfectly? In short, no!</p><p>Prompts rarely arrive fully formed. In this case, I started with a vague prompt, then refined and tested it until I found one that worked better for my needs. This is a key difference I&rsquo;ve noticed between people who get good results from an LLM and those who feel frustrated.</p><p>It&rsquo;s useful to learn how to write effective prompts, or &ldquo;meta prompts&rdquo; (where you get AI to write the prompt for you), and run rapid iterations so you can get something that works for you. Here it took around five minutes to get to a prompt that worked well for this exercise.</p><p>You can also turn to examples published online (Matt Pocock&rsquo;s skills are a clear standout), but it&rsquo;s useful to learn how to create your own skills/prompts, based on your own unique workflow and preferences.</p><p>With that said, we&rsquo;ve carved out our idea: a simple &ldquo;surface&rdquo; for capturing ideas and turning those into articles (with the source of truth being an MDX in an Astro blog).</p><p>Now to define the headline features. That&rsquo;s next, in Part 2.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">AI Can&rsquo;t Solve It All: What Frontend Devs Still Hate Working On</h4></div><div class="col-8"><p class="u-fs16 u-mb0">What still causes the most friction when building modern web applications? <a target="_blank" href="https://www.telerik.com/blogs/ai-cant-solve-all-what-120-frontend-developers-say-they-still-hate-working">120+ developers at JSNation and React Summit weigh in.</a></p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17374525.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:23c4afbf-be58-4e27-8443-2bfe893aab86</id>
    <title type="text">Getting Started with Angular Signal Forms</title>
    <summary type="text">Learn the basics of Angular Signal Forms, including models, validation and two-way synchronization, to build reactive forms with confidence.</summary>
    <published>2026-07-07T12:13:54Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17374437/getting-started-angular-signal-forms"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn the basics of Angular Signal Forms, including models, validation and two-way synchronization, to build reactive forms with confidence.</span></p><p>Angular version 21.0 introduced one of the most exciting and awaited features: Signal Forms. Traditionally, there have been two types of forms:</p><ol><li>Template Forms</li><li>Reactive Forms</li></ol><p>Angular 21.0 introduced a new form type:</p><ol start="3"><li>Signal Forms</li></ol><p>And now,&nbsp;<a href="https://www.telerik.com/blogs/angular-22-evolution-modern-angular" target="_blank">Angular 22</a> makes Signal Forms stable.&nbsp;Signal Forms are a combination of Signal-based reactivity and forms. In my opinion, Signal Forms are the future of forms and user input in Angular.</p><p>This article gives you a basic introduction to Signal Forms and shows you how to work with models, validation and two-way synchronization.</p><h2 id="first-signal-form">First Signal Form</h2><p>Signal-based forms use a new form function. It creates a form from a writable signal model, where the model is the source of truth, and any change in the form or the model is automatically reflected in the other.</p><p>Let&rsquo;s start by creating an interface to represent the user:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IUser</span> <span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
    password<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Next, we create a model that will be used to create the form, as shown below. As mentioned earlier, the model must be a writable signal.</p><pre class=" language-ts"><code class="prism  language-ts">user <span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>IUser<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span>  
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><p>We can create a signal-based form using the <code>form()</code> function from the <code>@angular/forms/signals</code>.</p><pre class=" language-ts"><code class="prism  language-ts">loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>That&rsquo;s it. You have created a signal-based form in Angular.</p><p>The form function returns a <code>FieldTree</code>, where each field is represented as a signal. In other words, the form function produces a data structure in which every field is a signal enriched with signal-based properties such as value, dirty, invalid and others.</p><p>To better understand this structure, let&rsquo;s print the following values:</p><pre class=" language-ts"><code class="prism  language-ts">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">loginForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">valid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">invalid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">dirty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">touched</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">errors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>As shown in the example above, the email field is a signal, and all of its properties are signals as well. Because both the field and its properties are signals, you can use them directly in the template, as demonstrated below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.password<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>To use <code>formField</code>, import it into the component class, as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> form<span class="token punctuation">,</span> FormField <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/forms/signals'</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-login'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>FormField<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./login.html'</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./login.css'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Login</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p>As discussed earlier, the <code>form()</code> function creates a form from the given model, where the model is the single source of truth, so changes in the form update the model and changes in the model update the form.</p><p>In simple words, the model and the form are connected through two-way data binding. This means that when the model signal changes, the form value updates accordingly, and when the form value changes, the model updates as well.</p><p>To demonstrate this, read the model signal value inside an effect, as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token function">effect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre><p>As soon as you start typing in the form, you can read the updated value in the effect. Similarly, when you change the model signal value, the form value is reflected as well.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">this</span><span class="token punctuation">.</span>user<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  email<span class="token punctuation">:</span> <span class="token string">'a@a.com'</span><span class="token punctuation">,</span>
  password<span class="token punctuation">:</span><span class="token string">'abc'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">loginForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// updated value of the form</span>
</code></pre><p>In summary, in signal-based forms, the model used by the form and the form itself are connected via two-way data binding. Updating one automatically updates the other.</p><h3 id="adding-validations">Adding Validations</h3><p>The <code>form()</code> function in Signal Forms makes it simple to add validators to form fields. You can pass a schema function to the <code>form()</code> function to add validators to the form.</p><p>In Signal Forms, validations are defined using a schema function. You pass this schema function as the second parameter to the <code>form()</code> function.</p><p>You can add the required validators to the email and password fields as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span><span class="token punctuation">(</span>schema<span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
  <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span><span class="token punctuation">{</span>message<span class="token punctuation">:</span><span class="token string">'email is required'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span><span class="token punctuation">{</span>message<span class="token punctuation">:</span><span class="token string">'email is not valid'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>password<span class="token punctuation">,</span><span class="token punctuation">{</span>message<span class="token punctuation">:</span><span class="token string">'password is required'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>We have added the required and email built-in validators and used the message option to provide custom error messages.</p><p>As discussed earlier, in a Signal Form, all properties of a field are signals. This allows you to use them directly. For example, to display validation error messages for the email field, as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
  Email
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
@if (loginForm.email().invalid() &amp;&amp; loginForm.email().touched()) {
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    @for (error of loginForm.email().errors(); track error.kind) {
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
    }
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
}
</code></pre><p>In the same way, error messages for the password field can be displayed as below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Password
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.password<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    @if (loginForm.password().invalid() &amp;&amp; loginForm.password().touched()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @for (error of loginForm.password().errors(); track error.kind) {
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    }
</code></pre><h3 id="submitting-the-form">Submitting the Form</h3><p>To complete the form, you can add submit functionality by importing the <code>submit()</code> function and using that to submit the form.</p><pre class=" language-ts"><code class="prism  language-ts">  <span class="token function">onSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">:</span> Event<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">submit</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> u <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">userModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Logging in with:'</span><span class="token punctuation">,</span> u<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>The <code>submit()</code> function runs the logic only when the form is valid.</p><p>In the template, the form submit event can bind to the <code>onSubmit ()</code> function using event binding, as shown below. You can also disable the submit button when the form is invalid.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSubmit($event)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    // other code for fields &hellip;..
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">[disabled]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm().invalid()<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Login<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre><h3 id="complete-signal-based-login-form">Complete Signal-based Login Form</h3><p>Putting everything together, the login form using Signal Forms can be implemented as shown below.</p><p>The IUser interface is created as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IUser</span> <span class="token punctuation">{</span>
    email<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span> 
    password <span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span> 
<span class="token punctuation">}</span>
</code></pre><p>The Login component using a Signal Form is created as shown below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> signal<span class="token punctuation">,</span> WritableSignal <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> IUser <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../user'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> email<span class="token punctuation">,</span> form<span class="token punctuation">,</span> FormField<span class="token punctuation">,</span> required<span class="token punctuation">,</span> submit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/forms/signals'</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-login'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>FormField<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./login.html'</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./login.css'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Login</span> <span class="token punctuation">{</span>

  userModel<span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>IUser<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>password<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'password is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">onSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">:</span> Event<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">submit</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> u <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">userModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Logging in with:'</span><span class="token punctuation">,</span> u<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the template, the form can be created as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSubmit($event)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Email
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    @if (loginForm.email().invalid() &amp;&amp; loginForm.email().touched()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @for (error of loginForm.email().errors(); track error.kind) {
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    }

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Password
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.password<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    @if (loginForm.password().invalid() &amp;&amp; loginForm.password().touched()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @for (error of loginForm.password().errors(); track error.kind) {
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">[disabled]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm().invalid()<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Login<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre><h3 id="understanding-forms-models">Understanding Forms Models</h3><p>Signal Forms are backed by a model, which is a writable signal. When the model value changes, the form updates automatically. Likewise, when the user interacts with the form, the model is updated. In this way, the model and the form are connected through two-way binding, which means changes in one are reflected in the other.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/model-signal-form.png?sfvrsn=a528e8f8_2" alt="Model and Signal Form exchange change updates" /></p><p>It is always best practice to use an interface to define the model. For example, if we are creating a form to edit a product, we can define a type for it as shown below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IProduct</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span>
    name<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    price<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span>
    description<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    category<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span> 
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IProductForm</span> <span class="token keyword">extends</span> <span class="token class-name">Omit</span><span class="token operator">&lt;</span>IProduct<span class="token punctuation">,</span> <span class="token string">'id'</span> <span class="token operator">|</span> <span class="token string">'category'</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p>Now to edit the product, fetch it from the API using the resource API as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">    idToFetch <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    productsResource <span class="token operator">=</span> <span class="token function">resource</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        params<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>idToFetch<span class="token punctuation">,</span>
        loader<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> params <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">let</span> id <span class="token operator">=</span> params<span class="token punctuation">;</span>
            <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`http://localhost:3000/product/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>response<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`HTTP error! status: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>response<span class="token punctuation">.</span>status<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">return</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> Promise<span class="token operator">&lt;</span>IProductForm<span class="token operator">&gt;</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>We have received the product data to be updated from the API. In the next step, we will create a signal-based form to bind this data and allow the user to update the product.</p><pre class=" language-ts"><code class="prism  language-ts">   productUpdateModel <span class="token operator">=</span> signal<span class="token operator">&lt;</span>IProductForm<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        name<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
        price<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
        description<span class="token punctuation">:</span> <span class="token string">''</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    productForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productUpdateModel<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>That&rsquo;s it. Now, in the template, use the <code>formField</code> directive to display the fetched product data in the form, as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSubmit($event)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Name
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.name<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Price
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.price<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Description
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.description<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">[disabled]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm().invalid()<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Update<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>To update the product, let&rsquo;s add an input field and a button to load the product.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>Update Product Id : &lt;input #productIdInput type="number" [value] ='idToFetch()'/&gt;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>fetchProduct(+productIdInput.value)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Load Product<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>To fetch the updated product, set the signal accordingly. There are multiple ways to bind the value returned from the API to the <code>productUpdateModel</code>. You can either use <code>productResource.value()</code> directly in the template or assign it as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">   <span class="token function">fetchProduct</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>idToFetch<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">hasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>productUpdateModel<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
</code></pre><p>As you see from the above example, the form model and form fields are in two-way data-binding synchronisation, and changes flow bidirectionally between them.</p><p>The interaction between user input and the model follows these steps:</p><ol><li>The user enters text or selects a value from the dropdown.</li><li>The <code>formField</code> directive detects the change.</li><li>The corresponding <code>FieldState</code> is updated.</li><li>The model signal is updated accordingly.</li></ol><p>This flow is illustrated in the diagram below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/user-input-model-interaction.png?sfvrsn=1c3ac370_2" alt="user inputs. formField directive detects the change. FieldState updated. Model signal updates" /></p><p>The flow between the model and the user input follows the steps below:</p><ol><li>Use code to <code>set()</code> or <code>update()</code> signal model</li><li>Notifies all subscribers</li><li>Field state updates</li><li><code>formField</code> directive updates the input element</li></ol><p>This flow is illustrated in the diagram below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/set-update-signal-model.png?sfvrsn=19cf05a3_2" alt="set() or update() signal model. Notifies all subscribers. Field state updates. formField directive updates input element." /></p><p>Two-way data synchronization can be better understood by the following simple code example.</p><pre class=" language-ts"><code class="prism  language-ts">count <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span> v<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  countInput <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">updateCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>count<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>c <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> v<span class="token punctuation">:</span> c<span class="token punctuation">.</span>v <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>And on the template:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>countInput.v<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>updateCount()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>update count<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Count: {{ count().v }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>When you run the above code, you will see that the input and model value are in sync with each other.</p><h2 id="optional-fields">Optional Fields</h2><p>Always use explicit TypeScript type to define the model. So to create a login form create a type like below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IUser</span> <span class="token punctuation">{</span>
    email<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span> 
    password <span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span> 
    rememeberme<span class="token operator">?</span><span class="token punctuation">:</span> <span class="token keyword">boolean</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>You use them to create a signal form as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">  userModel<span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>IUser<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    rememberMe<span class="token punctuation">:</span> <span class="token keyword">null</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>When you define a form using explicit types as shown above, the resulting field tree is fully type-safe. For example, <code>loginForm.email</code> is inferred as <code>FieldTree&lt;string&gt;</code>, and any attempt to access a property that doesn&rsquo;t exist will produce a compile-time error. In the code below, TypeScript will infer type of email as string.</p><pre class=" language-ts"><code class="prism  language-ts">email <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">.</span>email<span class="token punctuation">;</span>
</code></pre><p>And to set the optional field:</p><ul><li>Set the value explicitly to null</li><li>For input fields such <code>&lt;input type=&rdquo;text&rdquo; /&gt;</code>, set the value to empty string.</li><li>Do not use undefined</li></ul><p>Fields explicitly set to undefined are omitted from the field tree. A model defined as <code>{ value: undefined }</code> behaves the same as <code>{}</code>. Accessing that field returns undefined instead of a <code>FieldTree</code> instance.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/optional-fields.png?sfvrsn=916d9551_2" alt="Optional fields. Use null for optional fields. Do not use undefined, as it won’t be part of FieldTree." /></p><h2 id="nested-objects-in-model">Nested Objects in Model</h2><p>You can use nested objects to create a form like below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IProduct</span> <span class="token punctuation">{</span>
    id<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span>
    name<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    price<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span>
    description<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    category<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    vendor <span class="token punctuation">:</span> IVendor<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IVendor</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span>
    name<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    email<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>
    phone<span class="token punctuation">:</span><span class="token keyword">string</span><span class="token punctuation">;</span>   
<span class="token punctuation">}</span>
</code></pre><p>Next, you can create the form using the nested object as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">   productModel <span class="token operator">=</span> signal<span class="token operator">&lt;</span>IProduct<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
    name<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    price<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
    description<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    category<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>  
    vendor<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
      name<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
      email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
      phone<span class="token punctuation">:</span> <span class="token string">''</span>
    <span class="token punctuation">}</span> 
   <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

   productForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productModel<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the template, you can access nested object properties using dot notation, as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">(submit)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSubmit($event)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.name<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>Vendor Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.vendor.name<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Before moving to the validation section, note that the form model and the domain model are two different concepts and should be treated separately.</p><p>Your API response may map directly to the domain model, but you should define a dedicated form model when working with signal-based forms.</p><p>We will explore this distinction in more detail in a separate article.</p><h2 id="validations">Validations</h2><p>You pass validation rules to the Signal Forms using a schema. You pass schema as second parameter to the form function.</p><pre class=" language-ts"><code class="prism  language-ts">  userModel<span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span>IUser<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>password<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'password is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>As shown above, you provide a schema definition along with validation rules to apply validations to the respective fields of the form.</p><p>The schema function gets a <code>SchemaPathTree</code> object that lets us define the validation rules. The schema function runs at the time of initialization, and validation runs automatically whenever field values change.</p><p>On the template, you can use the validation as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">&gt;</span></span>
        Email
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">[formField]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loginForm.email<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
    @if (loginForm.email().invalid() &amp;&amp; loginForm.email().touched()) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>error<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @for (error of loginForm.email().errors(); track error.kind) {
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>{{ error.message }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    }
</code></pre><p>Validation works in these steps:</p><ol><li>Define validation rules in schema</li><li>Validation rules runs when filed value changes</li><li>Validation errors are propagated as signals</li><li>UI automatically updates when validation state changes</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/define-validation-rules-flow.png?sfvrsn=d710c039_2" alt="Define validation rules. Automatic execution of validation rules. Validation error propagates as Signals. Reactive update of UI on validation state changes" /></p><p>There are two types of validations:</p><ol><li>Synchronous validation &ndash; <code>required()</code>, <code>email()</code>, etc.</li><li>Asynchronous validation &ndash; <code>validateHttp()</code></li></ol><p>When a field value changes, Angular runs validation in the sequence:</p><ol><li>First it runs all synchronous validations.</li><li>If all synchronous validation pass, then it runs asynchronous validation.</li><li>After that, it updates the field state signal values such as <code>valid()</code>, <code>invalid()</code>, <code>errors()</code> and <code>pending()</code>.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/sync-validations-flow.png?sfvrsn=d7f77ce4_2" alt="Flow chart. Run synchronous validations. Passed – no or Run async validation. Update field state." /></p><p>Angular provides these built-in validation rules:</p><ol><li><code>required()</code></li><li><code>email()</code></li><li><code>min()</code></li><li><code>max()</code></li><li><code>minLength()</code></li><li><code>maxLength()</code></li><li><code>pattern()</code></li></ol><p>You can apply <code>required()</code> and <code>email()</code> validation on email field as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>When you have multiple validation rules applied, each rule runs independently and can cause form to be invalid.</p><p>Angular Signal Forms make it straightforward to implement custom validations. For example, if you want to verify that the email belongs to the nomadcoder domain, you can easily add a custom validator as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">  loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>userModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>schema<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'email is not valid'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token function">validate</span><span class="token punctuation">(</span>schema<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> value <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">'@nomadcoder.ai'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token punctuation">{</span>
          kind<span class="token punctuation">:</span> <span class="token string">'emailDomain'</span><span class="token punctuation">,</span>
          message<span class="token punctuation">:</span> <span class="token string">'Email must end with @nomadcoder.ai'</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In upcoming articles, we will get into details of custom validation and asynchronous validation.</p><h2 id="form-field-and-its-signal-properties">Form Field and Its Signal Properties</h2><p>The <code>form</code> function returns a <code>FieldTree</code> that represents all properties of the model. Each property is exposed as a signal, and each property signal includes a set of attributes that are also implemented as signals.</p><p>When you access a field from the field tree, as shown below, you can retrieve its associated attributes as illustrated:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/field-tree-attributes.png?sfvrsn=d73e4df6_2" alt="After  the next line has  and a list of attributes comes up" /></p><p>The various signal attributes are as below:</p><ol><li><code>value()</code></li><li><code>dirty()</code></li><li><code>hidden()</code></li><li><code>errors</code></li><li><code>errorSummary</code></li><li><code>valid</code></li><li><code>invalid</code></li><li><code>pending</code></li><li><code>submitting</code></li><li>Etc.</li></ol><p>As all these are <code>signals()</code>, they can be directly used on the template. I hope now you understand Angular Signal Forms. In coming articles, we will go deeper into:</p><ol><li>asynchronous validators</li><li>custom validators</li></ol><p>I hope you find this article useful. Thanks for reading.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Angular Signals: Building a Reactive Countdown Timer</h4></div><div class="col-8"><p class="u-fs16 u-mb0">A comprehensive tutorial for experienced Angular developers to learn <a target="_blank" href="https://www.telerik.com/blogs/angular-signals-building-reactive-countdown-timer">Angular Signals by building a practical countdown timer</a> application with computed signals and effects.</p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17374437.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:c92d89d9-25b7-41e4-bb56-1df47761789e</id>
    <title type="text">AI Can’t Solve It All: Here’s What 120+ Frontend Developers Say They Still Hate Working On</title>
    <summary type="text">What still causes the most friction when building modern web applications? 120+ developers at JSNation and React Summit weigh in.</summary>
    <published>2026-07-06T14:05:08Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Kathryn Grayson Nanz </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17373868/ai-cant-solve-all-what-120-frontend-developers-say-they-still-hate-working"/>
    <content type="text"><![CDATA[<p><span class="featured">What still causes the most friction when building modern web applications? 120+ developers at JSNation and React Summit weigh in.</span></p><p>While we were at JSNation and React Summit (<a href="https://www.telerik.com/blogs/check-out-amazing-projects-progress-gitnation-hackathon" target="_blank">read about our hackathon there</a>!), we wanted to take advantage of our booth space to do a little user research. We asked folks who stopped by to answer a simple question for us: <strong>What still causes the most friction when building modern web applications?</strong></p><p>Instead of running a formal survey, we set up a whiteboard, handed folks a sticky note and a sharpie, and invited them to air their grievances. Over the two days of the combined conferences, we collected 120+ responses across two prompts:</p><ul><li><strong>Day 1 (JS Nation):</strong> <em>What&rsquo;s the most annoying frontend task or component to build from scratch?</em></li><li><strong>Day 2 (React Summit):</strong> <em>What does AI still get wrong when building UI in React?</em></li></ul><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/1781254429274.jpg?sfvrsn=45fc2fa8_2" /></p><p>The responses were (at least to me) surprisingly consistent. While frameworks, tooling and AI assistants continue to evolve, many of the age-old pain points haven&rsquo;t disappeared. Turns out, it sucked to build a date picker 10 years ago and it still sucks today. </p><h2 id="building-ui-components-is-still-a-challenge">Building UI Components Is Still a Challenge</h2><p>We left the first question open-ended, allowing folks to pick between tasks and components that they found annoying. Personally, I was expecting to see more tasks than components&mdash;especially now that we can AI-generate components fairly quickly&mdash;but that&rsquo;s not what happened. In fact, the split between individual components and tasks was a fairly even split. </p><p><strong>Date picker components</strong> topped the list, with developers calling out everything from timezone handling to accessibility and date ranges. Unsurprisingly, <strong>AI</strong> is next up&mdash;adopting any new technology is going to come with some pain points and process adjustments. <strong>Accessibility</strong> was in third place with several callouts about struggling with compliance and testing, specifically. </p><table><style>table,
 th,
    td {
      border: 1px;
      border-color: #bdbdba;
      border-style: dotted;
      border-collapse: collapse;
      padding: 0in 5.4pt 0in 5.4pt;
    }
  </style>
 <thead><tr><th>Theme</th><th>Mentions</th></tr></thead><tbody><tr><td>Date pickers</td><td>9</td></tr><tr><td>AI-related work (including prompt engineering, dealing with AI-generated designs, AI features in components, skill writing and chatbot components)</td><td>8</td></tr><tr><td>Accessibility (including WCAG compliance, testing and mentions of specific challenging components such as calendars and comboboxes)</td><td>7</td></tr><tr><td>Requirements &amp; development process (including scope creep, non-technical coworkers, client management)</td><td>6</td></tr><tr><td>Data grids &amp; tables</td><td>5</td></tr><tr><td>Rich text editors</td><td>4</td></tr><tr><td>Design systems &amp; theming</td><td>4</td></tr><tr><td>Comboboxes</td><td>4</td></tr></tbody></table><br /><h2 id="ai-has-become-part-of-the-workflow-and-part-of-the-friction">AI Has Become Part of the Workflow&mdash;and Part of the Friction</h2><p>As you can see in the results above, even before we introduced an AI-specific discussion on Day 2 developers were already talking about AI. But when we asked specifically about AI-generated React code, the conversation shifted from whether AI is useful to where it still struggles<em>.</em></p><table><thead><tr><th>Theme</th><th>Mentions</th></tr></thead><tbody><tr><td>React architecture</td><td>6</td></tr><tr><td>CSS &amp; styling</td><td>4</td></tr><tr><td>Effects &amp; async logic</td><td>2</td></tr><tr><td>Animation</td><td>2</td></tr></tbody></table><br /><p>The top complaint was related to React architecture. Developers repeatedly mentioned AI-generated code that:</p><ul><li>Violates the rules of hooks</li><li>Creates unnecessary <code>useState</code> calls</li><li>Places state outside components</li><li>Generates new components instead of reusing existing ones</li><li>Produces code without understanding project requirements</li><li>Includes poor quality CSS</li></ul><h2 id="some-pain-points-refuse-to-go-away">Some Pain Points Refuse to Go Away</h2><p>Across both days, several themes kept resurfacing. Accessibility appeared on both walls, suggesting that AI hasn&rsquo;t eliminated many of the challenges developers face when building inclusive interfaces. Developers also repeatedly mentioned:</p><ul><li>Design systems</li><li>Figma-to-code workflows</li><li>Localization</li><li>Testing</li><li>State management</li><li>Performance</li><li>CSS</li></ul><p>These aren&rsquo;t new problems&mdash;and many of them have to do with very human aspects of software development such as coordination across teams, inclusivity, creating work for a global audience and user testing.</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/screenshot-2026-06-30-at-2-00-50-pm.png?sfvrsn=c0402f64_2" height="700" style="max-width:100%;height:auto;" title="Screenshot 2026-06-30 at 2.00.50 PM" width="728" alt="" sf-size="942727" /></p><h2 id="so-what-does-all-this-mean">So? What Does All This Mean</h2><p>The difficulty now (as it always has been) is in the integration of tools into cohesive systems. The tools have changed, but the challenge has not. Frontend developers today are spending their time wrestling with accessibility, architecture, complex UI components, evolving requirements and figuring out how to integrate AI into real production workflows.</p><p>AI is clearly changing how developers build software, but it hasn&rsquo;t eliminated the need for thoughtful engineering. In many cases, it&rsquo;s shifted developers&rsquo; attention toward reviewing, refining and improving generated code rather than writing every line themselves. Whether that&rsquo;s an improvement or not is something only time will tell. </p><p>The good news is that many of the component-centric frustrations that developers shared at our booth&mdash;date pickers, data grids, accessibility, design systems and more&mdash;all have something in common: they&rsquo;re problems with existing solutions.</p><p>Modern component libraries exist so developers can focus on building the unique parts of their applications instead of spending weeks recreating foundational UI. Likewise, AI tools are most effective when paired with production-ready building blocks that help developers generate better code, faster. </p><p>Investing in the right UI foundation can remove much of the friction developers told us they&rsquo;re still experiencing today. We may not have the answer to <em>every</em> frontend development struggle, but there are plenty that the <a href="https://www.telerik.com/home.aspx" target="_blank">Progress Telerik and Kendo UI</a> libraries can help address today.</p><img src="https://feeds.telerik.com/link/10827/17373868.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:c7659abf-70b7-4ba4-a7d1-5ece28dc3d4a</id>
    <title type="text">A Developer’s Guide to State Management with Effector</title>
    <summary type="text">Learn to build a simple app that shows how Effector handles state, async operations and UI updates. The app will allow users add, update, delete and load todos from an API.</summary>
    <published>2026-07-06T12:53:56Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Christian Nwamba </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17373825/developers-guide-state-management-effector"/>
    <content type="text"><![CDATA[<p>Learn to build a simple app that shows how Effector handles state, async operations and UI updates. The app will allow users add, update, delete and load todos from an API.</p><p>State management in React can get complicated quickly. Most libraries make you choose between simple and powerful. Simple tools break as your app grows or become difficult to manage. Powerful tools require you to write a lot of setup/config code before anything works. And when you need to handle async operations or derive state from multiple sources, you&rsquo;re writing custom logic from scratch all over again.</p><p><a target="_blank" href="https://effector.dev/">Effector</a> works differently. It is event-driven in the sense that you tell the app what happened (an event), the data updates in the store and the UI updates accordingly. Side effects are handled cleanly, and TypeScript works without extra setup. Instead of dispatching actions and writing reducers, you simply fire events that your stores react to.</p><h2 id="prerequisites">Prerequisites</h2><ul><li>Understanding of JavaScript/<a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a></li><li>Basic familiarity with <a target="_blank" href="https://react.dev/">React</a></li></ul><h2 id="project-setup">Project Setup</h2><p>We&rsquo;re going to build a to-do app to see how Effector handles state, async operations and UI updates. The app will let users add, update, delete and load todos from an API. We&rsquo;ll use Vite to set up a React + TypeScript project.</p><p>Open your terminal and run the following command:</p><pre class=" language-shell"><code class="prism  language-shell">npm create vite@latest effector-todo -- --template react-ts 
</code></pre><p>Once that is done, run the following command to navigate into your project:</p><pre class=" language-shell"><code class="prism  language-shell">cd effector-todo
npm install
</code></pre><p>Run this command to install Effector dependencies:</p><pre class=" language-shell"><code class="prism  language-shell">npm install effector effector-react
</code></pre><p>Effector works with any framework, but we need <code>effector-react</code> to connect it to React. The core <code>effector</code> package handles state management, while <code>effector-react</code> provides hooks like <code>useUnit</code> to access state in components.</p><h2 id="what-is-effector">What Is Effector?</h2><p>Effector is built around events. All you need to do is describe what happened and the store updates, and the UI will follow. If we compare that to Redux, you need an action, a reducer and a type constant to update a single value in a component.</p><p><a target="_blank" href="https://zustand.docs.pmnd.rs/learn/getting-started/introduction">Zustand</a> made this simpler by letting us call functions directly on the store, which felt like a relief. But async operations are where things get complicated. Suppose we want to save a todo to a database before updating the screen. The fetch call, the loading flag and error handling will all end up in one place, making the function grow messy.</p><p>Effector handles async operations differently. We wrap them in an effect, and the loading, success and failure states are all tracked automatically. With this, there is no need for manual flag management.</p><p>Then we also have <a target="_blank" href="https://react.dev/learn/passing-data-deeply-with-context">React Context</a>. If you change anything in a provider, your entire component tree re-renders. Effector avoids this by only updating the specific components subscribed to the store that actually changed. TypeScript also works out of the box. If you define types once in the store, they are known everywhere in the codebase.</p><p>The powerful thing about Effector is that it isn&rsquo;t tied to React alone. It gives you the flexibility to work with <a target="_blank" href="https://vuejs.org/">Vue</a>, <a target="_blank" href="https://svelte.dev/">Svelte</a> or any other framework.</p><h3 id="the-3-building-blocks">The 3 Building Blocks</h3><p>As mentioned earlier, Effector is built around three primitives called units: stores, events and effects. Everything in your app is one of these three things.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/effector-building-blocks.png?sfvrsn=d749548a_2" title="Effector’s building blocks" alt="Effector’s building blocks" /></p><ul><li><strong>A store</strong> holds your data, and it is a reactive container. When it changes, every component subscribed to it updates automatically. More precisely, every part of your UI that depends on it updates automatically. You never have to tell React that something has changed or trigger a re-render. The store handles that.</li><li><strong>Events</strong> are signals. They represent things that happen in your app, such as a button being clicked, a form being submitted or a user typing something. An event doesn&rsquo;t contain logic itself, it just announces what happened and carries the relevant data (the payload). This separation is intentional. Because an event is just a signal, you can wire it to any store or effect without the UI caring. The React button just triggers the event, so it doesn&rsquo;t need to know what happens next. That&rsquo;s the store&rsquo;s job.</li><li><strong>Effects</strong> are where async operations live. Anytime your app needs to talk to the outside world (fetch data, write to an API or read from localStorage), that goes in an effect. The reason effects exist as a separate primitive is that async operations have a lifecycle. They start, they either succeed or fail, and the UI needs to reflect each of those states. In most libraries, you manage this yourself with <code>useState</code> hooks and <code>try/catch</code> blocks scattered across your component. Effector handles it automatically. Every effect gives you a <code>loading</code> state, a <code>success</code> state and an <code>error</code> state out of the box. All you need to do is connect them, and you&rsquo;re done.</li></ul><h2 id="building-the-todo-store">Building the Todo Store</h2><p>Create a src/store.ts file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> createStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector"</span><span class="token punctuation">;</span>

<span class="token keyword">type</span> Todo <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
  text<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  done<span class="token punctuation">:</span> <span class="token keyword">boolean</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> $todos <span class="token operator">=</span> createStore<span class="token operator">&lt;</span>Todo<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the code above, we have a <code>Todo</code> type for TypeScript, which is just the shape of one item in our todos array, a single todo. The <code>$</code> prefix is Effector&rsquo;s convention for signaling that this is a <code>store</code>, not a regular <code>variable</code>. Because we passed <code>Todo[]</code> as the type, everywhere we use <code>$todos</code>, TypeScript already knows exactly what&rsquo;s inside it. The code above is our entire data layer for todos.</p><h2 id="creating-the-events">Creating the Events</h2><p>A store on its own doesn&rsquo;t do much. We mentioned earlier that events are one of the three building blocks in Effector, and this is where we create them. Update your <code>src/store.ts</code> file with the following:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> createStore<span class="token punctuation">,</span> createEvent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> addTodo <span class="token operator">=</span> createEvent<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> toggleTodo <span class="token operator">=</span> createEvent<span class="token operator">&lt;</span><span class="token keyword">number</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> deleteTodo <span class="token operator">=</span> createEvent<span class="token operator">&lt;</span><span class="token keyword">number</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Here we have three events that can happen in the app. <code>addTodo</code> carries a string, which is the text of the new todo. <code>toggleTodo</code> and <code>deleteTodo</code> carry a number which is the ID of the todo to act on.</p><p>One thing to notice here is that there&rsquo;s no logic. <code>addTodo</code> doesn&rsquo;t know how todos are stored or what happens when it fires. It&rsquo;s just a signal. This is what we described earlier when we said that the button that fires the event doesn&rsquo;t need to know what happens next.</p><h2 id="connecting-events-to-the-store">Connecting Events to the Store</h2><p>Right now, the store and the events exist independently, nothing connects them. That&rsquo;s what <code>.on()</code> does. Update your s<code>rc/store.ts</code> with the following:</p><pre class=" language-ts"><code class="prism  language-ts">$todos
<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>addTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> text<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span>
  <span class="token operator">...</span>state<span class="token punctuation">,</span>
  <span class="token punctuation">{</span> id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> text<span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token keyword">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>toggleTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> id<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
  state<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
    todo<span class="token punctuation">.</span>id <span class="token operator">===</span> id<span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token operator">...</span>todo<span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token operator">!</span>todo<span class="token punctuation">.</span>done <span class="token punctuation">}</span> <span class="token punctuation">:</span> todo
  <span class="token punctuation">)</span>
<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>deleteTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> id<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
  state<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todo<span class="token punctuation">.</span>id <span class="token operator">!==</span> id<span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Each <code>.on()</code> method takes two parameters: the event to listen for, and a function that describes how the state should change. The function receives the current state and the event payload, then returns a new state. It never mutates the previous state; instead, it always returns a new value.</p><p>In the code above, when <code>addTodo</code> fires, we spread the existing todos and add a new one. When <code>toggleTodo</code> fires, we find the todo with that ID and toggle its <code>done</code> value. When <code>deleteTodo</code> fires, we filter that todo out of the array.</p><p>That&rsquo;s the complete data layer for our todo app. There are no classes and no reducers. Just a store, three events and three <code>.on()</code> handlers describing exactly what changes when each event fires.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">KendoReact vs. OSS: What You Can Actually Get for Free (and What You Can&rsquo;t)</h4></div><div class="col-8"><p class="u-fs16 u-mb0">If you&rsquo;ve reached the point where <a target="_blank" href="https://www.telerik.com/blogs/kendoreact-vs-oss-what-actually-get-free-what-you-cant">free UI libraries are starting to cause friction</a>, it may be time to consider whether they&rsquo;re still the right choice for your team&mdash;and your app.</p></div></div><hr class="u-mb3" /></aside><h2 id="connecting-to-react">Connecting to React</h2><p>Our store exists, the events are wired up, but our UI doesn&rsquo;t know any of that yet. This is where <code>effector-react</code> comes in. It gives you a single hook, <code>useUnit</code>, that connects your components to your stores.</p><h3 id="reading-state-with-useunit">Reading State with useUnit</h3><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> useUnit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector-react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> $todos <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./store"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> todos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$todos<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p><code>useUnit</code> subscribes the component to <code>$todos</code>. When the store changes, the component re-renders with the new value. If nothing changes, it doesn&rsquo;t re-render.</p><p>We don&rsquo;t have context providers wrapping our app here. Compare this to how you would do the same with Context:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token operator">&lt;</span>TodoContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> todos<span class="token punctuation">,</span> setTodos <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>App <span class="token operator">/</span><span class="token operator">&gt;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>TodoContext<span class="token punctuation">.</span>Provider<span class="token operator">&gt;</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> todos <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>TodoContext<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Every time <code>setTodos</code> is called, every component inside that provider re-renders. As you can see, Effector gives us a much cleaner approach. With Effector, there&rsquo;s no provider. All we have to do is just import the store and call <code>useUnit</code>.</p><p>Create an <code>App.tsx</code> file in your <code>src</code> directory if you haven&rsquo;t already, and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useUnit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector-react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> $todos<span class="token punctuation">,</span> addTodo<span class="token punctuation">,</span> toggleTodo<span class="token punctuation">,</span> deleteTodo <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./store"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> todos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$todos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>input<span class="token punctuation">,</span> setInput<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleAdd</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>input<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">addTodo</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">setInput</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>min-h-screen bg-gray-50 p-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>max-w-2xl mx-auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-3xl font-bold text-gray-900 mb-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          Effector Todo
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow p-6 mb-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
              <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
              <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>input<span class="token punctuation">}</span></span>
              <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setInput</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">onKeyPress</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>key <span class="token operator">===</span> <span class="token string">"Enter"</span> <span class="token operator">&amp;&amp;</span> <span class="token function">handleAdd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Add a new todo...<span class="token punctuation">"</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500<span class="token punctuation">"</span></span>
            <span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
              <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleAdd<span class="token punctuation">}</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors<span class="token punctuation">"</span></span>
            <span class="token punctuation">&gt;</span></span>
              Add
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow divide-y<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token punctuation">{</span>todos<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token punctuation">(</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 text-gray-500 text-center<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              No todos yet<span class="token punctuation">.</span> Add one above<span class="token operator">!</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
          <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>
            todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 flex items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                  <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                  <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span></span>
                  <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-5 h-5 text-blue-600 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">/&gt;</span></span>
                <span class="token operator">&lt;</span>span className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token string">`flex-1 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>todo<span class="token punctuation">.</span>done <span class="token operator">?</span> <span class="token string">"line-through text-gray-400"</span> <span class="token punctuation">:</span> <span class="token string">"text-gray-900"</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">}</span><span class="token operator">&gt;</span>
                  <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                  <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">deleteTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-3 py-1 text-sm text-red-600 hover:bg-red-50 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">&gt;</span></span>
                  Delete
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">)</span><span class="token punctuation">)</span>
          <span class="token punctuation">)</span><span class="token punctuation">}</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>`
</code></pre><p>In the code above, you&rsquo;ll notice we&rsquo;re not attaching any state logic in our <code>App</code> component, all thanks to Effector. It doesn&rsquo;t care how todos are stored, added or deleted. All it does is read <code>$todos</code> and trigger events when something happens.</p><p>The only place we&rsquo;re using <code>useState</code> is for the <code>input</code> field, which makes sense since that&rsquo;s just local UI state which doesn&rsquo;t need to live in the store.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/todo-app-using-effector-stores.gif?sfvrsn=3054f22d_2" title="Todo app using Effector stores" alt="Todo app using Effector stores" /></p><h3 id="derived-store-with-.map">Derived Store with .map()</h3><p>Our store works, and the UI is connected, but most apps aren&rsquo;t as straightforward as our todo app currently is. At some point, you might want to show only completed todos in one place, count remaining tasks somewhere else or filter by priority in another component. You can already see where this is heading.</p><p>What comes to mind first is filtering inside each component. That works until you need to change how something works and realize your logic is scattered across the app, where changing one thing breaks another.</p><p>Effector handles this with derived states. Instead of rewriting the same logic or recomputing values across components, you derive them once.</p><p>Let&rsquo;s update our <code>store.ts</code> file with these derived stores:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> $completedTodos <span class="token operator">=</span> $todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todos<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
  todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todo<span class="token punctuation">.</span>done<span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> $activeTodos <span class="token operator">=</span> $todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todos<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
  todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">!</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> $remainingCount <span class="token operator">=</span> $todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>
  <span class="token punctuation">(</span>todos<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todos<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">!</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">)</span><span class="token punctuation">.</span>length
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><code>$todos.map()</code> is a method we call on a store. This might look familiar, but it&rsquo;s not the same as JavaScript&rsquo;s <code>array.map()</code>. When this one is called on a store, it returns a new store.</p><p>In Effector, when you call <code>.map()</code> on a store, it creates a new store that watches the original one. Whenever <code>$todos</code> updates, the derived store runs your transformation function and updates itself. This way, everything stays in sync automatically.</p><p>Effector also follows immutability. Nothing gets changed in place. Every time you derive something, you&rsquo;re creating a new value instead of modifying the existing one, and the transformation function handles that for you.</p><p>Let&rsquo;s see this in action by updating our <code>App.tsx</code> file to look like so:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token comment">//App.tsx</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useUnit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector-react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  $activeTodos<span class="token punctuation">,</span>
  $completedTodos<span class="token punctuation">,</span>
  $remainingCount<span class="token punctuation">,</span>
  addTodo<span class="token punctuation">,</span>
  toggleTodo<span class="token punctuation">,</span>
  deleteTodo<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./store"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> activeTodos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$activeTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> completedTodos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$completedTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> remainingCount <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$remainingCount<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>input<span class="token punctuation">,</span> setInput<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleAdd</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>input<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">addTodo</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">setInput</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>min-h-screen bg-gray-50 p-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>max-w-2xl mx-auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex items-center justify-between mb-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-3xl font-bold text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Effector Todo<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-gray-500 text-sm<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">{</span>remainingCount<span class="token punctuation">}</span> <span class="token punctuation">{</span>remainingCount <span class="token operator">===</span> <span class="token number">1</span> <span class="token operator">?</span> <span class="token string">"task"</span> <span class="token punctuation">:</span> <span class="token string">"tasks"</span><span class="token punctuation">}</span> remaining
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow p-6 mb-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
              <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
              <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>input<span class="token punctuation">}</span></span>
              <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setInput</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">onKeyPress</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>key <span class="token operator">===</span> <span class="token string">"Enter"</span> <span class="token operator">&amp;&amp;</span> <span class="token function">handleAdd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Add a new todo...<span class="token punctuation">"</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500<span class="token punctuation">"</span></span>
            <span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
              <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleAdd<span class="token punctuation">}</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors<span class="token punctuation">"</span></span>
            <span class="token punctuation">&gt;</span></span>
              Add
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

        <span class="token punctuation">{</span>activeTodos<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow divide-y mb-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">{</span>activeTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 flex items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                  <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                  <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span></span>
                  <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-5 h-5 text-blue-600 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">/&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                  <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">deleteTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-3 py-1 text-sm text-red-600 hover:bg-red-50 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">&gt;</span></span>
                  Delete
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">}</span>

        <span class="token punctuation">{</span>completedTodos<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-500 mb-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              Completed
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow divide-y opacity-60<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">{</span>completedTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 flex items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                    <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                    <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span></span>
                    <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                    <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-5 h-5 text-blue-600 rounded<span class="token punctuation">"</span></span>
                  <span class="token punctuation">/&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 line-through text-gray-400<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                    <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                    <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">deleteTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                    <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-3 py-1 text-sm text-red-600 hover:bg-red-50 rounded<span class="token punctuation">"</span></span>
                  <span class="token punctuation">&gt;</span></span>
                    Delete
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>As seen above, the app component stays clean and just does what it is supposed to do.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/todo-app-with-derived-stores.gif?sfvrsn=f18cac48_2" title="A basic todo app with derived stores" alt="A basic todo app with derived stores" /></p><h2 id="async-operations-with-effects">Async Operations with Effects</h2><p>Every app eventually needs to talk to the outside world, and it may be through fetching data, saving something to a server or reading from storage. This is where most state management solutions make you manually create a loading flag, set it to true before the request, set it back to false when it finishes, handle the error case and clean up if the component unmounts. You end up writing the same boilerplate every time.</p><p>The good thing about Effector is that it has a dedicated concept for this called Effects.</p><h2 id="creating-an-effect">Creating an Effect</h2><p>Let&rsquo;s update our <code>store.ts</code> file by first adding a new import called <code>createEffect</code>. This handles fetching data and, more generally, any kind of side effect.</p><p>We&rsquo;ll also use a dummy API to fetch some todos and define the type of each todo we expect back.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> createStore<span class="token punctuation">,</span> createEvent<span class="token punctuation">,</span> createEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector"</span><span class="token punctuation">;</span>

<span class="token keyword">type</span> ApiTodo <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
  todo<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  completed<span class="token punctuation">:</span> <span class="token keyword">boolean</span><span class="token punctuation">;</span>
  userId<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> loadTodosFx <span class="token operator">=</span> <span class="token function">createEffect</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://dummyjson.com/todos?limit=5"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> data<span class="token punctuation">.</span>todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">:</span> ApiTodo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span> todo<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
    text<span class="token punctuation">:</span> todo<span class="token punctuation">.</span>todo<span class="token punctuation">,</span>
    done<span class="token punctuation">:</span> todo<span class="token punctuation">.</span>completed<span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the code above, <code>createEffect</code> wraps an async function. The <code>Fx</code> suffix is an Effector convention in the sense that just as <code>$</code> signals a store, <code>Fx</code> signals an effect. Anyone reading the code immediately knows what they&rsquo;re dealing with.</p><p>The function inside is just a regular async function that fetches data, transforms it and returns it.</p><p>Effector offers three things out of the box:</p><ul><li><code>loadTodosFx.pending</code>: A store that is true while the effect is running and false when it finishes</li><li><code>loadTodosFx.doneData</code>: An event that fires with the return value when the effect succeeds</li><li><code>loadTodosFx.fail</code>: An event that fires with the error if something goes wrong</li></ul><p>We don&rsquo;t write any of this, and you&rsquo;ll see it in action when we connect the effects to the store.</p><h2 id="connecting-the-effect-to-the-store">Connecting the Effect to the Store</h2><p>We&rsquo;ll wire <code>doneData</code> to <code>$todos</code> the same way we wired events with <code>.on()</code>.</p><p>In your store.ts file, update the <code>$todos</code> connection to include the effect:</p><pre class=" language-ts"><code class="prism  language-ts">$todos
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>addTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> text<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span>
    <span class="token operator">...</span>state<span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      text<span class="token punctuation">,</span>
      done<span class="token punctuation">:</span> <span class="token keyword">false</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>toggleTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> id<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
    state<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
      todo<span class="token punctuation">.</span>id <span class="token operator">===</span> id <span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token operator">...</span>todo<span class="token punctuation">,</span> done<span class="token punctuation">:</span> <span class="token operator">!</span>todo<span class="token punctuation">.</span>done <span class="token punctuation">}</span> <span class="token punctuation">:</span> todo<span class="token punctuation">,</span>
    <span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>deleteTodo<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> id<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> state<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todo<span class="token punctuation">.</span>id <span class="token operator">!==</span> id<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>loadTodosFx<span class="token punctuation">.</span>doneData<span class="token punctuation">,</span> <span class="token punctuation">(</span>_<span class="token punctuation">,</span> todos<span class="token punctuation">:</span> Todo<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> todos<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The only new thing in the code above is the last <code>.on()</code> call. Before now, the store was reacting to events we triggered manually. Now it&rsquo;s also reacting to the result of an async operation.</p><p>When <code>loadTodosFx.doneData</code> fires (which happens when the request succeeds), the store replaces the current todos with whatever came back from the API.</p><h2 id="using-the-fx-in-the-component">Using the Fx in the Component</h2><p>Now update your App.tsx to import <code>loadTodosFx</code> and read the loading state:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useUnit <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector-react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  $activeTodos<span class="token punctuation">,</span>
  $completedTodos<span class="token punctuation">,</span>
  $remainingCount<span class="token punctuation">,</span>
  addTodo<span class="token punctuation">,</span>
  toggleTodo<span class="token punctuation">,</span>
  deleteTodo<span class="token punctuation">,</span>
  loadTodosFx<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./store"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> activeTodos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$activeTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> completedTodos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$completedTodos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> remainingCount <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>$remainingCount<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> loadTodos <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>loadTodosFx<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> isLoading <span class="token operator">=</span> <span class="token function">useUnit</span><span class="token punctuation">(</span>loadTodosFx<span class="token punctuation">.</span>pending<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token punctuation">[</span>input<span class="token punctuation">,</span> setInput<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">handleAdd</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>input<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">addTodo</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">setInput</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>min-h-screen bg-gray-50 p-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>max-w-2xl mx-auto<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex items-center justify-between mb-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-3xl font-bold text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Effector Todo<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>

          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex items-center gap-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-teal-700 text-2xl font-extrabold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">{</span>remainingCount<span class="token punctuation">}</span> <span class="token punctuation">{</span>remainingCount <span class="token operator">===</span> <span class="token number">1</span> <span class="token operator">?</span> <span class="token string">"task"</span> <span class="token punctuation">:</span> <span class="token string">"tasks"</span><span class="token punctuation">}</span><span class="token punctuation">{</span><span class="token string">" "</span><span class="token punctuation">}</span>
              remaining
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>

            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
              <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">loadTodos</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">disabled</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>isLoading<span class="token punctuation">}</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50<span class="token punctuation">"</span></span>
            <span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">{</span>isLoading <span class="token operator">?</span> <span class="token string">"Loading..."</span> <span class="token punctuation">:</span> <span class="token string">"Fetch Todos"</span><span class="token punctuation">}</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow p-6 mb-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex gap-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
              <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span>
              <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>input<span class="token punctuation">}</span></span>
              <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">setInput</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">onKeyPress</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>key <span class="token operator">===</span> <span class="token string">"Enter"</span> <span class="token operator">&amp;&amp;</span> <span class="token function">handleAdd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
              <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Add a new todo...<span class="token punctuation">"</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500<span class="token punctuation">"</span></span>
            <span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
              <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>handleAdd<span class="token punctuation">}</span></span>
              <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors<span class="token punctuation">"</span></span>
            <span class="token punctuation">&gt;</span></span>
              Add
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

        <span class="token punctuation">{</span>activeTodos<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow divide-y mb-6<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">{</span>activeTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 flex items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                  <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                  <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span></span>
                  <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-5 h-5 text-blue-600 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">/&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 text-gray-900<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                  <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">deleteTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                  <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-3 py-1 text-sm text-red-600 hover:bg-red-50 rounded<span class="token punctuation">"</span></span>
                <span class="token punctuation">&gt;</span></span>
                  Delete
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
            <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">}</span>

        <span class="token punctuation">{</span>completedTodos<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-sm font-medium text-gray-500 mb-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              Completed
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white rounded-lg shadow divide-y opacity-60<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">{</span>completedTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>todo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>p-4 flex items-center gap-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
                    <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span>
                    <span class="token attr-name">checked</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>done<span class="token punctuation">}</span></span>
                    <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">toggleTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                    <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>w-5 h-5 text-blue-600 rounded<span class="token punctuation">"</span></span>
                  <span class="token punctuation">/&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex-1 line-through text-gray-400<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                    <span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
                    <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token function">deleteTodo</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
                    <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>px-3 py-1 text-sm text-red-600 hover:bg-red-50 rounded<span class="token punctuation">"</span></span>
                  <span class="token punctuation">&gt;</span></span>
                    Delete
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
              <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">}</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Two things changed in this component. First, we imported <code>loadTodosFx</code>, which is now called when the &ldquo;Load Todos&rdquo; button is clicked. Second, <code>loadTodosFx.pending</code> is read with <code>useUnit</code>, which automatically gives us the loading state. The button disables itself while loading, the label switches and todos appear when the fetch is complete.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/fetching-todos-from-api.gif?sfvrsn=2f979803_2" title="Fetching todos from an API" alt="Fetching todos from an API" /></p><h2 id="connecting-units-with-sample">Connecting Units with Sample</h2><p>We have stores, events and effects, but sometimes you need them to talk to each other. When one thing happens, it triggers something else. That&rsquo;s what <code>sample</code> is for. The idea here is straightforward: when a clock fires, read from a source, optionally transform the data and send it to a target.</p><p>Before we look at the code, let&rsquo;s break down what each of those terms actually means:</p><ul><li><strong>clock</strong> &ndash; The trigger. This is what starts everything. It can be an event, an effect or even another store. When it fires, everything else follows.</li><li><strong>source</strong> &ndash; The data you want to read at that moment. Usually a store.</li><li><strong>fn</strong> &ndash; An optional function to transform the data before it goes anywhere. If you don&rsquo;t need to transform anything, you can skip it.</li><li><strong>target</strong> &ndash; Where the result goes. Can be a store, an event or an effect.</li></ul><p>Here is an example:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> sample <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"effector"</span><span class="token punctuation">;</span>

<span class="token function">sample</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  clock<span class="token punctuation">:</span> someEvent<span class="token punctuation">,</span>    <span class="token comment">// when this fires...</span>
  source<span class="token punctuation">:</span> $someStore<span class="token punctuation">,</span>  <span class="token comment">// grab the current value of this store...</span>
  fn<span class="token punctuation">:</span> <span class="token punctuation">(</span>sourceValue<span class="token punctuation">,</span> clockPayload<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">...</span><span class="token punctuation">,</span> <span class="token comment">// optionally transform...</span>
  target<span class="token punctuation">:</span> anotherEvent <span class="token comment">// and send it here</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Now, let&rsquo;s go through a real example from our todo app. Right now, when you add a todo, the list updates locally. But in a real app, you&rsquo;d want to reload from the server after adding so everything is in sync. Without <code>sample</code>, you&rsquo;d handle that inside the component by calling <code>addTodo</code>, then manually calling <code>loadTodosFx</code> right after. That works, but now that logic is tied to one specific button in one specific component.</p><p>Add this to your store.ts file:</p><pre class=" language-ts"><code class="prism  language-ts">Import <span class="token punctuation">{</span>sample<span class="token punctuation">}</span> <span class="token keyword">from</span> &ldquo;effector&rdquo;<span class="token punctuation">;</span> 
<span class="token function">sample</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  clock<span class="token punctuation">:</span> addTodo<span class="token punctuation">,</span>
  target<span class="token punctuation">:</span> loadTodosFx<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Now, instead of completely replacing the todos when the request finishes, we&rsquo;ll merge the data from the API with what we already have locally.</p><p>In your <code>store.ts</code> file, update the last <code>.on()</code> call to look like this:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>loadTodosFx<span class="token punctuation">.</span>doneData<span class="token punctuation">,</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> apiTodos<span class="token punctuation">:</span> Todo<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> apiIds <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span>apiTodos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> t<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> localTodos <span class="token operator">=</span> state<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token operator">!</span>apiIds<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>t<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token operator">...</span>apiTodos<span class="token punctuation">,</span> <span class="token operator">...</span>localTodos<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Every time <code>addTodo</code> fires from anywhere in our app, from any component, <code>loadTodosFx</code> runs automatically. The component has no idea this is happening. It just calls <code>addTodo</code>, and Effector handles the rest.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-07/connecting-units-to-sample.gif?sfvrsn=73c69da4_2" title="Connecting Units to Sample" alt="Connecting Units to Sample" /></p><h2 id="conclusion">Conclusion</h2><p>Honestly, Effector isn&rsquo;t the right tool for every project. If you&rsquo;re building something small with just a few components and basic state, stick with <code>useState</code> and <code>useContext</code>. Save Effector for when your app genuinely starts getting messy.</p><p>It shines in specific scenarios like when you&rsquo;re dealing with async operations that need proper loading and error handling, when multiple unrelated components need to access the same state, when you&rsquo;re computing the same derived data all over the place, or when you catch yourself copy-pasting the same async logic everywhere.</p><p>We&rsquo;ve only scratched the surface here. Effector can do much more, but we&rsquo;ve covered the basics and core concepts, which are the foundation for everything else. If you want to go deeper, check out the <a target="_blank" href="https://effector.dev/en/introduction/get-started/">Effector documentation</a>.</p><img src="https://feeds.telerik.com/link/10827/17373825.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:ece91e7b-3c59-42b7-935d-f8ca6ba998c3</id>
    <title type="text">Nuxt 4 Notes with AppWrite</title>
    <summary type="text">Build a basic to-do app using Nuxt 4 and Appwrite for hands-on setup and TablesDB experience.</summary>
    <published>2026-06-30T20:22:47Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Jonathan Gamble </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17370580/nuxt-4-notes-appwrite"/>
    <content type="text"><![CDATA[<p><span class="featured">Build a basic to-do app using Nuxt 4 and Appwrite for hands-on setup and TablesDB experience.</span></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/screenshot_2026-03-14_200837.png?sfvrsn=b6bf0ef8_2" alt="Notes app! Hello Jane. Three notes that look like sticky notes." /></p><p>Nuxt has gone through a few updates since Nuxt 4, and Appwrite has some new ways of handling data with <code>TableDB</code>. Let&rsquo;s build a TODO app!</p><p>⚠️ This app assumes you have basic Nuxt knowledge and can create an Appwrite database.</p><h2 id="tldr">TL;DR</h2><p>We are building Nuxt Notes, a basic to-do app using Nuxt 4 and <a target="_blank" href="https://appwrite.io/">Appwrite</a>. I could not find any good documentation on setting up Appwrite correctly with Nuxt 4, nor on handling the new <code>TablesDB</code> class. This will cover both.</p><h2 id="appwrite">Appwrite</h2><ol><li>Create a new <a target="_blank" href="https://appwrite.io/">Appwrite</a> project. This project is called <code>notes-app</code>.</li><li>For this example, we create a new database called <code>notes</code>. Copy the Database ID for later.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image00.png?sfvrsn=7fff64c5_6" alt="databases - with ID" /></p><ol start="3"><li>Since we are not doing anything complex, the table can also be called <code>notes</code>.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image01.png?sfvrsn=8ec0d8e6_6" alt="Notes. Rows, Columns, Indexes, Activity, Usage, Settings" /></p><ol start="4"><li>We need to configure our tables to have a <code>note</code> string column and an <code>author</code> string column.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-2.png?sfvrsn=263c6d5_2" alt="note string column and an author string column" /></p><ol start="5"><li>A user should be able to fully CRUD. You can find this in <code>Settings</code> and then <code>Permissions</code>.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-3.png?sfvrsn=36f30b34_2" alt="Permissions" /></p><h2 id="nuxt-4-setup">Nuxt 4 Setup</h2><p>Now we need to configure Nuxt 4 before we handle the <code>notes</code>.</p><ol><li>Create a new <a target="_blank" href="https://nuxt.com/">Nuxt 4</a> app.</li><li><a target="_blank" href="https://tailwindcss.com/docs/installation/framework-guides/nuxt">Configure Tailwind.</a></li><li>Install Appwrite with <code>npm i appwrite</code>.</li></ol><h3 id="env">ENV</h3><p>First, update <code>nuxt.config.ts</code> to read from <code>.env</code> file.</p><pre class=" language-tsx"><code class="prism  language-tsx">import tailwindcss from "@tailwindcss/vite";

export default defineNuxtConfig({
  compatibilityDate: "2025-07-15",
  devtools: { enabled: true },
  css: ['./app/assets/css/main.css'],
  vite: {
    plugins: [
      tailwindcss(),
    ],
  },
  runtimeConfig: {
    public: {
      appwriteEndpoint: '',
      appwriteProjectId: '',
      appwriteDatabaseId: '',
    },
  },
});
</code></pre><ul><li>Yes, the variables will be empty strings! They automatically get replaced by the ENV data. We use <code>NUXT_PUBLIC_</code> as the public prefix to allow it to be available on the client.</li><li>New words will be capitalized in the config file.</li></ul><p>We need to copy our environmental variables into <code>.env</code> from our Appwrite application.</p><pre class=" language-tsx"><code class="prism  language-tsx">NUXT_PUBLIC_APPWRITE_PROJECT_ID=69168c49003b2c79aafe
NUXT_PUBLIC_APPWRITE_DATABASE_ID=69b5c9ff0024d4feae10
NUXT_PUBLIC_APPWRITE_ENDPOINT=https://nyc.cloud.appwrite.io/v1
</code></pre><ul><li>Your data will be completely different!</li></ul><p>You can find this in project <code>Settings</code>.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-4.png?sfvrsn=52e5a9c2_2" alt="API credentials" /></p><h3 id="app-file-at-appapp.vue">App File at app/app.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;template&gt;
  &lt;main class="flex items-center flex-col gap-5 p-5"&gt;
    &lt;h1 class="text-3xl font-bold text-red-800"&gt;Notes App!&lt;/h1&gt;
    &lt;Auth /&gt;
  &lt;/main&gt;
&lt;/template&gt;
</code></pre><ul><li>We need to display our app, the <code>Auth</code> component will be created in a bit!</li></ul><h3 id="loader-at-appcomponentsloading.vue">Loader at app/components/loading.vue</h3><p>We can create a simple loading spinner.</p><pre class=" language-tsx"><code class="prism  language-tsx">&lt;template&gt;
  &lt;div
    class="animate-spin rounded-full h-10 w-10 border-4 border-b-current border-gray-200"
  &gt;&lt;/div&gt;
&lt;/template&gt;
</code></pre><h2 id="configure-appwrite-at-apppluginsappwrite.ts">Configure Appwrite at app/plugins/appwrite.ts</h2><p>I believe it is bad practice to export data directly and import it in components. Nuxt has <code>plugins</code> for loading data the correct way.</p><pre class=" language-tsx"><code class="prism  language-tsx">import { ID, TablesDB } from 'appwrite'
import { Client, Account, Permission, Role, Query } from 'appwrite'

export default defineNuxtPlugin(() =&gt; {

    const config = useRuntimeConfig()

    const client = new Client()

    const tables = new TablesDB(client)

    client
        .setEndpoint(config.public.appwriteEndpoint)
        .setProject(config.public.appwriteProjectId)

    const account = new Account(client)

    const databaseId = config.public.appwriteDatabaseId

    return {
        provide: {
            ID,
            Permission,
            Role,
            Query,
            client,
            account,
            tables,
            databaseId
        }
    }
})
</code></pre><ul><li>Load the config data with <code>useRuntimeConfig()</code></li><li>Set the <code>client</code>, <code>tables</code> and <code>account</code> classes to be reusable</li><li>Initialize the project with our ENV files with <code>client.setEndpoint().setProject()</code>, and export the <code>databaseId</code></li></ul><h2 id="authentication-composables">Authentication Composables</h2><p>Appwrite does not have an observable like <a target="_blank" href="https://firebase.google.com/">Firebase</a> or <a target="_blank" href="https://supabase.com/">Supabase</a>. You must manually grab the user when you need it with <code>account.get()</code>.</p><h3 id="user-composable-at-appcomposablesuse-user.ts">User Composable at app/composables/use-user.ts</h3><pre class=" language-tsx"><code class="prism  language-tsx">import type { Models } from "appwrite"

type User = Models.User&lt;Models.Preferences&gt;

export const useUser = () =&gt; {

    const { $account } = useNuxtApp()

    const user = useState&lt;{
        data: User | null,
        loading: boolean
    }&gt;('user', () =&gt; ({
        data: null,
        loading: true
    }))

    const getUser = async () =&gt; {
        try {
            user.value.loading = true
            user.value.data = await $account.get()
        } catch (error) {
            user.value.data = null
        } finally {
            user.value.loading = false
        }
        return user
    }

    return {
        user,
        getUser
    }
}
</code></pre><ul><li>Create a reusable <code>user</code> variable, and set it to be sharable from many components with <code>useState</code> instead of <code>ref</code> with the current user state.</li><li>We need to show a loading state while loading.</li><li><code>getUser</code> will have to be called on component mounting.</li></ul><h3 id="auth-composable-at-appcomposableuse-auth.ts">Auth Composable at app/composable/use-auth.ts</h3><pre class=" language-tsx"><code class="prism  language-tsx">import { AppwriteException } from "appwrite"

export const useAuth = () =&gt; {

    const { $account, $ID } = useNuxtApp()

    const { getUser } = useUser()

    const authError = ref&lt;string | null&gt;(null)

    const authForm = ref({
        email: "",
        password: "",
        name: ""
    })

    const login = async () =&gt; {
        
        const { email, password } = authForm.value
        
        try {
            await $account.createEmailPasswordSession({
                email,
                password
            })

            await getUser()

        } catch (error) {
            if (error instanceof AppwriteException) {
                authError.value = error.message
            }
            if (error instanceof Error) {
                authError.value = error.message
            }
            throw error
        }
    }

    const register = async () =&gt; {

        const { email, password, name } = authForm.value

        try {
            await $account.create({
                userId: $ID.unique(),
                email,
                password,
                name
            })

            await login()

        } catch (error) {
            if (error instanceof AppwriteException) {
                authError.value = error.message
            }
            if (error instanceof Error) {
                authError.value = error.message
            }
            throw error
        }

    }

    const logout = async () =&gt; {
        try {
            await $account.deleteSession({
                sessionId: "current"
            })

            await getUser()

        } catch (error) {
            if (error instanceof AppwriteException) {
                authError.value = error.message
            }
            if (error instanceof Error) {
                authError.value = error.message
            }
            throw error
        }
    }

    return {
        register,
        login,
        logout,
        authError,
        authForm
    }
}
</code></pre><ul><li>We must handle <code>login</code>, <code>register</code> and <code>logout</code>. We can also create a shared variable for <code>authError</code> and <code>authForm</code> containing the <code>email</code>, <code>password</code> and <code>name</code> data.</li><li>Most examples don&rsquo;t handle errors. We do here by sending a message to the <code>authError</code> signal.</li><li>We need to check for the correct error types, if there is an error.</li><li>Creating an account does not automatically log in the user.</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">await $account.create({
    userId: $ID.unique(),
    email,
    password,
    name
})
</code></pre><p>You must manually call login afterward.</p><pre class=" language-tsx"><code class="prism  language-tsx">await $account.createEmailPasswordSession({
    email,
    password
})

await getUser()
</code></pre><p>And we call <code>getUser</code> so that our <code>user</code> state signal gets updated reactively.</p><h3 id="auth-component-at-appcomponentsauth.vue">Auth Component at app/components/auth.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script setup lang="ts"&gt;
const { user, getUser } = useUser()
onMounted(getUser)
&lt;/script&gt;

&lt;template&gt;
  &lt;template v-if="user.loading"&gt;
    &lt;Loading /&gt;
  &lt;/template&gt;
  &lt;template v-else-if="user.data"&gt;
    &lt;Logout /&gt;
    &lt;Notes /&gt;
  &lt;/template&gt;
  &lt;template v-else&gt;
    &lt;LoginForm /&gt;
  &lt;/template&gt;
&lt;/template&gt;
</code></pre><ul><li>We call <code>getUser</code> on mount to load the user state.</li><li>We display loading if necessary.</li><li>We show login form if not logged in; otherwise we show logout with our notes component.</li></ul><h3 id="logout-component-at-appcomponentslogout.vue">Logout Component at app/components/logout.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script setup lang="ts"&gt;
const { logout } = useAuth()
const { user } = useUser()
&lt;/script&gt;

&lt;template&gt;
  &lt;h1&gt;Hello {{ user.data?.name }}&lt;/h1&gt;
  &lt;button
    type="button"
    @click="logout"
    class="rounded-lg bg-gray-200 px-4 py-2 text-sm font-medium text-gray-900 transition hover:bg-gray-300"
  &gt;
    Logout
  &lt;/button&gt;
&lt;/template&gt;
</code></pre><ul><li>We display the <code>name</code> using <code>useUser</code>, and create a link to <code>logout</code> using <code>useAuth</code>.</li></ul><h3 id="login-form">Login Form</h3><p>Let&rsquo;s handle registering and logging in!</p><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script setup lang="ts"&gt;
const { login, register, authError, authForm } = useAuth()

const isLogin = ref(true)
&lt;/script&gt;

&lt;template&gt;
  &lt;div
    class="mx-auto max-w-md rounded-xl border border-gray-200 bg-white p-6 shadow-sm"
  &gt;
    &lt;form class="space-y-3"&gt;
      &lt;input
        autocomplete="email"
        type="email"
        placeholder="Email"
        v-model="authForm.email"
        class="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm outline-none transition focus:border-gray-500"
      /&gt;

      &lt;input
        autocomplete="current-password"
        type="password"
        placeholder="Password"
        v-model="authForm.password"
        class="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm outline-none transition focus:border-gray-500"
      /&gt;

      &lt;template v-if="isLogin"&gt;
        &lt;p class="text-sm text-gray-600"&gt;
          Don't have an account?
          &lt;button
            type="button"
            @click="isLogin = false"
            class="text-blue-600 hover:underline"
          &gt;
            Register
          &lt;/button&gt;
        &lt;/p&gt;
      &lt;/template&gt;
      &lt;template v-else&gt;
        &lt;input
          autocomplete="name"
          type="text"
          placeholder="Name"
          v-model="authForm.name"
          class="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm outline-none transition focus:border-gray-500"
        /&gt;
        &lt;p class="text-sm text-gray-600"&gt;
          Already have an account?
          &lt;button
            type="button"
            @click="isLogin = true"
            class="text-blue-600 hover:underline"
          &gt;
            Login
          &lt;/button&gt;
        &lt;/p&gt;
      &lt;/template&gt;

      &lt;template v-if="isLogin"&gt;
        &lt;button
          type="button"
          @click="login"
          class="rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white transition hover:bg-gray-800"
        &gt;
          Login
        &lt;/button&gt;
      &lt;/template&gt;
      &lt;template v-else&gt;
        &lt;button
          type="button"
          @click="register"
          class="rounded-lg bg-gray-200 px-4 py-2 text-sm font-medium text-gray-900 transition hover:bg-gray-300"
        &gt;
          Register
        &lt;/button&gt;
      &lt;/template&gt;
      &lt;template v-if="authError"&gt;
        &lt;p class="mt-2 text-sm text-red-600"&gt;{{ authError }}&lt;/p&gt;
      &lt;/template&gt;
    &lt;/form&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><ul><li><code>isLogin</code> will toggle login versus registering.</li><li>We don&rsquo;t need to program any functions in our component, as this is all beautifully handled in our <code>useAuth</code> composable!</li><li>We could have created our reactive data directly in this component, but in this case it is automatically synced with the composable.</li></ul><h2 id="notes">Notes</h2><p>We need to add and remove notes.</p><h3 id="notes-composable-at-appcomposablesuse-notes.ts">Notes Composable at app/composables/use-notes.ts</h3><pre class=" language-tsx"><code class="prism  language-tsx">import { AppwriteException } from "appwrite"

type Note = {
    note: string,
    id: string
}

export const useNotes = () =&gt; {

    const notes = useState&lt;{
        data: Note[],
        loading: boolean
    }&gt;('notes', () =&gt; ({
        data: [],
        loading: false
    }))

    const newNote = ref('')

    const noteError = ref&lt;string | null&gt;(null)

    const { user } = useUser()

    const {
        $tables,
        $ID,
        $databaseId,
        $Permission,
        $Role,
        $Query
    } = useNuxtApp()

    const getNotes = async () =&gt; {

        if (!user.value.data) {
            throw new Error('User not authenticated')
        }

        const userId = user.value.data.$id

        try {
            notes.value.loading = true
            const { rows } = await $tables.listRows({
                databaseId: $databaseId,
                tableId: 'notes',
                queries: [
                    $Query.equal('author', userId)
                ]
            })

            notes.value.data = rows.map(row =&gt; ({
                note: row.note,
                id: row.$id
            }))
        } catch (error) {
            if (error instanceof AppwriteException) {
                noteError.value = error.message
            }
            if (error instanceof Error) {
                noteError.value = error.message
            }
            throw error
        } finally {
            notes.value.loading = false
        }
    }

    const addNote = async () =&gt; {

        const note = newNote.value.trim()

        const userData = user.value?.data

        if (!userData) {
            throw new Error('User not authenticated')
        }

        const userId = userData.$id

        // optimistically add note

        const rowId = $ID.unique()

        notes.value.data.push({
            note,
            id: rowId
        })

        newNote.value = ''

        try {
            await $tables.createRow({
                databaseId: $databaseId,
                tableId: 'notes',
                rowId,
                data: {
                    note,
                    author: userId
                },
                permissions: [
                    $Permission.read($Role.user(userId)),
                    $Permission.update($Role.user(userId)),
                    $Permission.delete($Role.user(userId))
                ]
            })

        } catch (error) {

            // remove optimistically added note
            notes.value.data = notes.value.data.filter(n =&gt; n.note !== note)

            newNote.value = note

            if (error instanceof AppwriteException) {
                noteError.value = error.message
            }
            if (error instanceof Error) {
                noteError.value = error.message
            }
            throw error
        }
    }

    const removeNote = async (id: string) =&gt; {

        // optimistically remove note
        const index = notes.value.data.findIndex(n =&gt; n.id === id)

        if (index === -1) {
            noteError.value = 'Note not found'
            return
        }

        const note = notes.value.data[index]!

        notes.value.data.splice(index, 1)

        try {
            await $tables.deleteRow({
                databaseId: $databaseId,
                tableId: 'notes',
                rowId: id
            })
        } catch (error: unknown) {
            // re-add optimistically removed note
            notes.value.data.splice(index, 0, note)
            if (error instanceof AppwriteException) {
                noteError.value = error.message
            }
            if (error instanceof Error) {
                noteError.value = error.message
            }
            throw error
        }
    }

    const resetNotes = () =&gt; {
        notes.value = {
            data: [],
            loading: false
        }
    }

    return {
        addNote,
        removeNote,
        notes,
        noteError,
        getNotes,
        resetNotes,
        newNote
    }
}
</code></pre><ul><li>We <code>getNotes</code> to display them, <code>addNotes</code> from the form, and <code>removeNotes</code> from the button.</li><li>There should be no case where a user can see notes without being logged in, but we handle that anyway.</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">const getNotes = async () =&gt; {

    if (!user.value.data) {
        throw new Error('User not authenticated')
    }
    ...
</code></pre><ul><li>We optimistically add notes to our <code>notes</code> signal, and if it fails, we remove them. This is what Firebase does automatically. We also optimistically remove them, and if it fails, add them back. This will create an extremely fast UI!</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">notes.value.data.push({
    note,
    id: rowId
})

...

// optimistically remove note
const index = notes.value.data.findIndex(n =&gt; n.id === id)

if (index === -1) {
    noteError.value = 'Note not found'
    return
}

const note = notes.value.data[index]!
</code></pre><ul><li>Appwrite handles permissions on create by the user that created them.</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">await $tables.createRow({
    databaseId: $databaseId,
    tableId: 'notes',
    rowId,
    data: {
        note,
        author: userId
    },
    permissions: [
        $Permission.read($Role.user(userId)),
        $Permission.update($Role.user(userId)),
        $Permission.delete($Role.user(userId))
    ]
})
</code></pre><ul><li>We also need the <code>database id</code> when we add a new <code>note</code>, and we want to match it with the user <code>author</code> it belongs to.</li><li>The <code>Role.user(userId)</code> gets created by the logged in <code>userId</code>.</li><li>Removing is simple:</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">await $tables.deleteRow({
    databaseId: $databaseId,
    tableId: 'notes',
    rowId: id
})
</code></pre><ul><li>Fetching requires a filter of the <code>userId</code>:</li></ul><pre class=" language-tsx"><code class="prism  language-tsx">const { rows } = await $tables.listRows({
    databaseId: $databaseId,
    tableId: 'notes',
    queries: [
        $Query.equal('author', userId)
    ]
})
</code></pre><ul><li><code>Query.equal</code> covers our <code>author</code> column filter.</li></ul><h3 id="add-a-note-at-appcomponentsadd-note.vue">Add a Note at app/components/add-note.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script lang="ts" setup&gt;
const { addNote, noteError, newNote } = useNotes()
&lt;/script&gt;

&lt;template&gt;
  &lt;form class="mx-auto flex max-w-md gap-2"&gt;
    &lt;textarea
      autocomplete="note"
      type="text"
      name="note"
      v-model="newNote"
      placeholder="Enter a note"
      class="flex-1 rounded-md border border-gray-300 px-3 py-2 text-sm outline-none focus:border-gray-500"
    /&gt;
    &lt;button
      type="submit"
      @click.prevent="addNote"
      class="rounded-md bg-black px-4 py-2 text-sm font-medium text-white hover:bg-gray-800"
    &gt;
      Add Note
    &lt;/button&gt;
  &lt;/form&gt;

  &lt;p v-if="noteError" class="mx-auto mt-2 max-w-md text-sm text-red-600"&gt;
    {{ noteError }}
  &lt;/p&gt;
&lt;/template&gt;
</code></pre><ul><li>Putting things in our composables makes our templates extremely clean. Again, we handle our errors with <code>noteError</code>.</li></ul><h3 id="notes-component-at-appcomponentsnotes.vue">Notes Component at app/components/notes.vue</h3><p>And we display our notes to each user.</p><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script lang="ts" setup&gt;
const { notes, removeNote, resetNotes, getNotes } = useNotes()

onMounted(getNotes)
onUnmounted(resetNotes)
&lt;/script&gt;

&lt;template&gt;
  &lt;p class="mb-4 text-center text-lg font-semibold text-gray-800"&gt;Notes&lt;/p&gt;
  &lt;template v-if="notes.loading"&gt;
    &lt;Loading /&gt;
  &lt;/template&gt;
  &lt;template v-else-if="notes.data.length"&gt;
    &lt;ul
      class="mx-auto mb-6 grid max-w-4xl grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"
    &gt;
      &lt;li
        v-for="note in notes.data"
        :key="note.id"
        class="relative min-h-45 -rotate-1 rounded-sm border border-yellow-200 bg-yellow-200 p-4 shadow-md"
      &gt;
        &lt;div
          class="absolute left-1/2 top-0 h-5 w-16 -translate-x-1/2 -translate-y-1/2 -rotate-3 bg-yellow-100/80 shadow-sm"
        /&gt;

        &lt;p class="pb-12 text-sm leading-6 text-gray-800"&gt;
          {{ note.note }}
        &lt;/p&gt;

        &lt;button
          type="button"
          class="absolute bottom-3 right-3 not-[]:px-3 py-1 hover:opacity-50"
          @click="removeNote(note.id)"
        &gt;
          ️
        &lt;/button&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/template&gt;
  &lt;template v-else&gt;
    &lt;p class="mb-6 text-center text-gray-500"&gt;No notes yet. Add one below!&lt;/p&gt;
  &lt;/template&gt;
  &lt;AddNote /&gt;
&lt;/template&gt;
</code></pre><ul><li>Notice we retrieve our notes on mounting, and we reset our notes signal on unmounting.</li><li>Notes also need a loading state since they are a separate async function.</li></ul><h2 id="app-flow">App Flow</h2><p>We can login or register, and each user has their own todos!</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-5.png?sfvrsn=9f012a0d_2" alt="notes app login" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-6.png?sfvrsn=d2d17d97_2" alt="user already exists" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-7.png?sfvrsn=27daa395_2" alt="Hello Jane! No notes yet. Add one below!" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-8.png?sfvrsn=b372e3b8_2" alt="four notes" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/chrome_d9qpokriur.gif?sfvrsn=ee6b8406_2" alt="Demo of adding and deleting notes" /></p><p><strong>Repo:</strong> <a target="_blank" href="https://github.com/jdgamble555/nuxt-notes-appwrite">GitHub</a></p><p> I don&rsquo;t have a demo because the free Appwrite project will pause after a certain time, but this demo should be pretty easy to clone.</p><p>Happy coding!</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Nuxt 4 Server Routes vs. Fetch Composables</h4></div><div class="col-8"><p class="u-fs16 u-mb0">See a Nuxt app load data from the server in a Server Component and using useFetch to see <a target="_blank" href="https://www.telerik.com/blogs/nuxt-4-server-routes-vs-fetch-composables">how Server Components and fetch mechanisms compare</a>.</p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17370580.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:25764796-2937-4908-aea5-7d0a72c05de6</id>
    <title type="text">Choosing the Right Telerik UI for Blazor Chart</title>
    <summary type="text">Which type of chart is best for your data set? Explore the different types of Blazor charts and get a guide of which to use in certain use cases.</summary>
    <published>2026-06-30T16:57:43Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Héctor Pérez </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17370448/choosing-right-telerik-ui-blazor-chart"/>
    <content type="text"><![CDATA[<p><span class="featured">Which type of chart is best for your data set? Explore the different types of Blazor charts and get a guide of which to use in certain use cases.</span></p><p>In data-driven applications, it is common to want to display information dynamically and visually. However, there are times when we have doubts about which type of chart to use in our applications.</p><p>Choosing the wrong type of chart can cause users to become confused or even distort the information by displaying it incompletely or with a layout that doesn&rsquo;t make much sense.</p><p>That is why this article is a roundup of the types of charts available in the Progress Telerik <a target="_blank" href="https://www.telerik.com/blazor-ui">UI suite for Blazor</a> and when to use each. Let&rsquo;s get to it!</p><h2 id="chart-types-in-telerik-ui-for-blazor">Chart Types in Telerik UI for Blazor</h2><p>Let&rsquo;s analyze the different types of <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/components/chart/overview">charts available in Telerik UI for Blazor</a>, as well as when to use them.</p><h3 id="column-chart">Column Chart</h3><p>The first type of chart, column, is perhaps the simplest. With this chart we can display vertical bars in which the height represents the value of each category. It&rsquo;s a quite versatile chart type, which is why it&rsquo;s very common to see it in applications and elsewhere. The chart looks like the following:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/simple-column-chart.png?sfvrsn=2ad90540_2" alt="Simple column chart" /></p><p>This type of chart is useful when we want to compare values across categories, show rankings or classifications, and visualize data where order does matter.</p><h3 id="bar-chart">Bar Chart</h3><p>The bar chart is the equivalent of the column chart but in a horizontal format. In the Telerik component <code>ChartSeriesType.Bar</code> is used and the category axis is on the vertical axis instead of horizontal:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/simple-bar-chart.png?sfvrsn=2e966c33_2" alt="Simple bar chart showing categories and values." /></p><p>This chart can be used when category names are long and you need more space to display them, when you want to show a horizontal comparison between values, and when you want to emphasize the difference in values between categories.</p><h3 id="line-chart">Line Chart</h3><p>The line chart displays a graph with connected points, which makes this chart ideal for showing trends over time. In the Telerik component it supports normal, step and smooth lines:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/simple-line-chart.png?sfvrsn=4c604b1_2" alt="Simple line chart showing an upward trend" /></p><p>This chart is suitable when we want to visualize temporal trends, compare different evolutions within the same period and when continuity between data points is relevant.</p><h3 id="area-chart">Area Chart</h3><p>This type of chart is similar to the line chart, with the difference that the space beneath the lines is filled with a semi-transparent color. This gives greater emphasis to the volume or magnitude of the data. In the Telerik component we can control the opacity using the <code>Opacity</code> property.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/area-chart-simple.png?sfvrsn=5e3dca17_2" alt="Simple area chart showing rising values over time" /></p><p>You can use this chart when you want to emphasize the volume of the data, their trend or when you want to show how different series overlap.</p><h3 id="pie-chart">Pie Chart</h3><p>The pie chart displays a circle divided into proportional slices for each value specified in the category. It only supports a single series, which makes it an ideal chart for showing the composition of a whole:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/simple-pie-chart.png?sfvrsn=56a76ea0_2" alt="Simple pie chart showing proportional data distribution" /></p><p>Some examples of when to use this type of chart are when you want to show a percentage distribution of data, while being mindful of the maximum number of slices so as not to overcrowd the chart. Likewise, when you want users to quickly understand portions of a whole and when you require the values to add up to 100%.</p><h3 id="donut-chart">Donut Chart</h3><p>This type of chart is similar to a pie chart but with a hole in the center. This hole can be used to display a highlighted data point or, as the Progress Telerik team has done, allow multiple series to be shown:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/donut-chart-simple.png?sfvrsn=89334033_2" alt="Simple donut chart with four colored segments" /></p><p>This chart is recommended for showing, in addition to the pie-chart scenarios, hierarchical relationships between data sets.</p><h3 id="scatter-chart">Scatter Chart</h3><p>The scatter chart displays a series of points defined by the <strong>x</strong> and <strong>y</strong> axes, with these being numeric data:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/scatter-plot-basic.png?sfvrsn=f64a9932_2" alt="Scatter plot showing correlated data points" /></p><p>This type of chart is ideal when you want to show a correlation between two numeric variables, such as the relationship between users connected in an application and a website&rsquo;s load time. It is also useful for identifying patterns, clusters, scientific data, among others.</p><h3 id="bubble-chart">Bubble Chart</h3><p>This chart is similar to the scatter chart in how it works, but adds a third dimension, which is the size of the bubble:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/simple-bubble-chart.png?sfvrsn=34686cbe_2" alt="Simple bubble chart showing values by size" /></p><p>The third dimension is useful for comparing entities with multiple metrics simultaneously.</p><h3 id="scatter-line-chart">Scatter Line Chart</h3><p>The scatter line chart is similar to the scatter chart, except that in this case the points are connected by lines:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/scatter-line-plot.png?sfvrsn=86d3bc9b_2" alt="Scatter plot with connecting line showing data relationship" /></p><p>This chart is convenient to use when you want to show the relationship between two variables while maintaining continuity in the data or trend.</p><h3 id="candlestick-chart">Candlestick Chart</h3><p>This candlestick-style chart is widely used in the financial sector, as it allows showing four values for a period: open, close, high and low. If we are talking about stocks in the securities market, the body of the candle represents the price from open to close, while the wicks, which are the thin lines above and below, show the period&rsquo;s high and low:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/candlestick-chart.png?sfvrsn=a9d98305_2" alt="Candlestick chart showing market price movements" /></p><p>This chart is suitable for showing financial movements or when you want to identify trading patterns.</p><h3 id="ohlc-chart-open-high-low-close">OHLC Chart (Open-High-Low-Close)</h3><p>This chart shows the same four values as the candlestick chart, but instead of using candle bodies, it uses horizontal marks. In this chart the horizontal values represent the open and close, while the lower and upper extremes show the maximum and minimum:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/ohlc-candlestick-chart.png?sfvrsn=3fafa6ef_2" alt="Candlestick OHLC chart" /></p><p>The use cases for this chart are the same as for the candlestick chart, but when you want a cleaner visualization. It is also ideal when you want to show many time periods, in which a candlestick chart would overlap the values.</p><h3 id="heatmap-chart">Heatmap Chart</h3><p>The heatmap displays a grid where color intensity represents the magnitude of a value across two dimensions:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/heatmap-chart-color-grid.png?sfvrsn=2f853608_2" alt="Heatmap showing color-coded intensity across a grid" /></p><p>If you are a software developer, you will surely recognize the image above, since GitHub shows a similar chart to display the commits you have made on an account. This demonstrates that the chart is ideal for showing an activity density in two dimensions and when you want to show behavior patterns across intersecting categories.</p><h3 id="radar-line-chart">Radar Line Chart</h3><p>This chart starts from a common center from which several axes radiate. Each axis represents a specific value, which are then connected to form a closed shape:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/radar-line-chart.png?sfvrsn=2ef60c49_2" alt="Radar line chart comparing multiple variables" /></p><p>It is very useful when you want to make profile comparisons, such as variables between LLM models or when you want to make before/after comparisons.</p><h3 id="radar-area-chart">Radar Area Chart</h3><p>This radar area chart is similar to the radar line chart, with the difference that the space of the formed shape is filled with a color:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/radar-area-chart-filled.png?sfvrsn=364cf4ed_2" alt="Filled radar area chart showing multivariate data" /></p><p>This chart works well to understand how different profiles overlap on the chart quickly.</p><h3 id="radar-column-chart">Radar Column Chart</h3><p>The radar column chart follows the same principle as the radar line and radar area charts, with the difference that it shows diagonal bars extending from the center:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/radar-column-chart.png?sfvrsn=5607c18f_2" alt="Radar column chart for comparison" /></p><p>By showing bars instead of connecting points, this chart is excellent for comparing individual values across categories and when an overlap in the radar area could make reading values difficult.</p><h3 id="range-area-chart">Range Area Chart</h3><p>The range area chart shows an area defined between two continuous lines defining the range between a minimum and a maximum value, similar to the area chart but not starting from zero:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/range-area-chart.png?sfvrsn=1a0018c5_2" alt="Range area chart showing high and low values." /></p><p>By displaying ranges, it is ideal in scenarios such as temperature ranges, error margins and when you need to emphasize a difference between continuous sequences of values.</p><h3 id="range-bar-chart">Range Bar Chart</h3><p>This chart lets you display ranges of values over a period of time using horizontal bars, whose position and length vary according to a from value and a to value:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/range-bar-chart.png?sfvrsn=d0c7eb72_2" alt="Horizontal range bar chart showing start and end values" /></p><p>This chart can help you show time ranges or durations, or compare ranges between categories or groups.</p><h3 id="range-column-chart">Range Column Chart</h3><p>It is the vertical version of the range bar chart. In this chart vertical bars are displayed, which vary according to the from and to values:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/range-column-chart.png?sfvrsn=13016741_2" alt="Range column chart showing min and max values" /></p><p>This chart could be useful to show ranges of scores between periods or when you need to emphasize both the minimum and the maximum of each category.</p><h3 id="waterfall-chart">Waterfall Chart</h3><p>This chart is based on a series of bars that show a cumulative value of sequential positive and negative values. Each bar starts where the previous one ended, which allows you to see the value&rsquo;s behavior after a period. In the Telerik component it is also possible to display columns with total or partial values:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/waterfall-chart-simple.png?sfvrsn=5b498a9d_2" alt="Waterfall chart showing sequential positive and negative values" /></p><p>Use cases for this chart include when you need to analyze cash flow over months, for budget and profitability analysis, among others.</p><h3 id="sankey-chart">Sankey Chart</h3><p>This Telerik component <code>TelerikSankey</code> displays a set of entities and links to represent the flow between them. In addition, the thickness of each link shows the value, allowing users to easily see the entity-to-value flow:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/sankey-diagram-flows.png?sfvrsn=be7afe80_2" alt="Sankey diagram showing flows between categories" /></p><p>Because of its flexibility, the Sankey chart is ideal for analyzing traffic distributions, breaking down budgets or redistributing resources.</p><h3 id="stock-chart">Stock Chart</h3><p>To use a stock chart, you should use the <code>TelerikStockChart</code> component, which is part of the Telerik UI for Blazor suite. This component is specifically designed for financial time series data. It supports types we&rsquo;ve already covered such as candlestick and OHLC, with the difference that it includes a navigator to select a specific time period:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/stock-market-line-chart.gif?sfvrsn=33fc642e_2" alt="Stock chart showing stock market price movements" /></p><p>This component is useful when you need to navigate time periods in financial data or to create trading dashboards or investment analysis.</p><h3 id="trendline-chart">Trendline Chart</h3><p>The last chart type we&rsquo;ll analyze is the trendline type. This chart isn&rsquo;t really a chart type where you define its own data; rather, it takes the data from an existing chart to reveal the trend of the data. The component supports several trend types: linear, average, exponential, logarithmic, among others:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/trendline-chart-simple.png?sfvrsn=68161b2c_2" alt="Simple trendline chart showing upward data trend" /></p><p>Some use cases for this chart type include revealing the overall direction of the data, smoothing fluctuations, performing forecasts, as well as conducting statistical analyses and validating patterns over time.</p><h3 id="decision-tree-for-selecting-the-best-chart">Decision Tree for Selecting the Best Chart</h3><p>After having analyzed the different types of charts that we can find in the Telerik UI for Blazor suite, I want to leave you a decision list that can help you select the best chart for your use case:</p><p><strong>Comparison &amp; Trends</strong><br />- If there is time or continuity -&gt; Use a line, area or scatter line chart<br />- If there are simple categories -&gt; Use a column or bar chart<br />- If there are long category names -&gt; Use a bar chart<br />- If you want to show underlying trends -&gt; Add a trendline</p><p><strong>Composition (Parts of a Whole)</strong><br />- For a single series -&gt; Use a pie or donut chart<br />- For multiple series -&gt; Use a donut chart<br />- For flows between domains -&gt; Use a Sankey diagram</p><p><strong>Relationships &amp; Distribution</strong><br />- With 2 variables -&gt; Use a scatter plot<br />- With 3 variables -&gt; Use a bubble chart<br />- For 2D density -&gt; Use a heatmap<br />- For multidimensional profiles -&gt; Use a radar chart (area, column or line)</p><p><strong>Ranges &amp; Cumulative Changes</strong><br />- To show the effect of changes -&gt; Use a waterfall chart<br />- For continuous ranges -&gt; Use a range area chart<br />- For time durations -&gt; Use a range bar chart<br />- For vertical ranges -&gt; Use a range column chart</p><p><strong>Specialized Data</strong><br />- For financial/price movement -&gt; Use a candlestick or stock chart</p><p>This list should help you make a better decision about when to use each type of chart.</p><h2 id="conclusion">Conclusion</h2><p>Throughout this article, we have taken a tour of the different types of charts that we can find in the Telerik suite for Blazor. This was aimed at understanding the structure of each one, how it looks and which are the best scenarios for their use. After this information, it&rsquo;s your turn to present your users&rsquo; data in different ways, always keeping in mind that their interpretation should be as simple as possible.</p><p>Ready to experiment with all these chart types? Telerik UI for Blazor comes with a free 30-day trial:</p><p><a href="https://www.telerik.com/try/ui-for-blazor" target="_blank" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/10827/17370448.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:1bd8e293-fa30-4fab-803e-f42e54e29d42</id>
    <title type="text">Check Out These Amazing Projects from the Progress x GitNation Hackathon!</title>
    <summary type="text">We hosted a hackathon in partnership with GitNation, and the response blew us away. In just 48 hours, we got over 30 finished projects! Check out our winners and some of our favorites.</summary>
    <published>2026-06-29T16:35:30Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Kathryn Grayson Nanz </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17369836/check-out-amazing-projects-progress-gitnation-hackathon"/>
    <content type="text"><![CDATA[<p><span class="featured">Our Progress x GitNation hackathon at React Summit and JSNation netted 30+ projects that blew us away. Check out our winners and some of our favorites.</span></p><p>A few weeks ago, the Progress team headed to Amsterdam for <a target="_blank" href="https://reactsummit.com/">React Summit</a> and <a target="_blank" href="https://jsnation.com/">JSNation</a>: two of the back-to-back biggest events on the JavaScript calendar. </p><p>Between the packed schedule, booth conversations, social events and time hanging out with a few hundred of your closest developer friends, it was a seriously week. Not to mention, our team finally got to spend some time together in-person&mdash;something that doesn&rsquo;t happen very often when you&rsquo;re scattered across the globe! Although we all left feeling exhausted (and at least in my case, wildly jet-lagged), it was absolutely worth the trip.</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/1781519496198.jpg?sfvrsn=819290e8_2" height="575" style="max-width:100%;height:auto;" title="1781519496198" width="1280" alt="Kiril, on stage at React Summit. " sf-size="105038" /></p><p>Our own Kiril Peyanski took the React Summit stage to deliver a talk on generative frontend, exploring a new paradigm where LLMs generate the logic that maps data to UI using React Server Components and Server Functions to make interfaces that adapt to the user. And when I tell you the room was packed, I mean <em>literally</em> standing room only and overflowing out the door!</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/1781519492695.jpg?sfvrsn=f86ecc35_2" height="963" style="max-width:100%;height:auto;" title="1781519492695" width="1280" alt="Kiril&#39;s talk, overflowing with attendees " sf-size="204170" /></p><p>As part of the conference, we also hosted a hackathon in partnership with <a target="_blank" href="https://gitnation.com/">GitNation</a>, challenging attendees to build something that makes tech conferences better. We left the specifics up to our hackers. It could mean better for attendees, better for speakers, better for organizers or something else entirely. We wanted to see how creative folks would get, and the response blew us away. The hackathon lasted just 48 hours, and we had over 30 finished projects!</p><p>After judging (which, let me tell you, was a real challenge), three projects stood out from the crowd:</p><p><strong>Our grand prize winners, <a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/502">HALLWAY</a>:</strong> The team behind HALLWAY built a mobile-first app that turns the chaos of a conference day into a personalized, connected flow. Answer a few quick questions, and it builds your schedule, fills your free gaps with curated intros to the right people, and places you in a small group for the evening. </p><p><strong>Our first runner-up, <a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/593">Conf Pilot</a>:</strong> Conf Pilot is an MCP server that brings live conference schedules directly into AI chat. Ask "what&rsquo;s next?" and instead of a wall of text, you get a fully interactive, themed widget with track filters, live countdown timers and calendar links&mdash;all without leaving your AI assistant. One of the first projects to use the new MCP Apps structured content pattern, and a seriously impressive build for a one-person submission! </p><p><strong>Our second runner-up, <a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/524">Stuck Stack</a>:</strong> Stuck Stack turns the conference into a live help marketplace. Post what you&rsquo;re blocked on, find someone nearby who can help you in five minutes, and watch blockers move across a live board from Open &rarr; Matched &rarr; Solved. Organizers get a real-time dashboard that can even detect when enough attendees are stuck on the same thing and suggest a pop-up help clinic on the spot. Clever, useful and beautifully designed.</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/1781519491888.jpg?sfvrsn=6fdf2f90_2" height="575" style="max-width:100%;height:auto;" title="1781519491888" width="1280" alt="The Progress team on stage with the overall winners, team HALLWAY " sf-size="113685" /></p><p>However, we couldn&rsquo;t give prizes to everyone&mdash;as much as we wished we could! When I tell you the judging was a challenge, it&rsquo;s because we had other submissions like these that were so, <em>so</em> impressive. While these unfortunately didn&rsquo;t end up placing, we do want to make sure they get their time in the sun as well, so you can also appreciate their incredible work! </p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/579">The Hallway</a></strong> took a new swing at the age-old problem of networking. Your AI agent walks into the conference before you do, negotiates with other attendees&rsquo; agents to find the right matches and only reveals identities once both humans consent. </p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/592">Unison</a></strong> tackled something nobody else touched&mdash;language barriers. It dubs conference talks in real-time, letting speakers present in one language while every attendee hears it in their own, with no headsets and about a three-second lag. Two-way, too: attendees can ask questions in their language and the speaker receives them in theirs.</p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/595">CrowdShift</a></strong> flipped the speaker experience on its head. Speakers normally prepare blind, with no idea who&rsquo;s actually in the room. CrowdShift pulls registration data and builds a continuously updated audience brief, so a speaker can see that their crowd shifted from 65% senior to 55% junior and adapt their talk in real time.</p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/588">ConferenceCast</a></strong> treated a multi-track conference like a TV broadcast: every room is a channel, and you get a personalized program guide with AI match scores, live session cards, countdown timers and a control-room dashboard for organizers to track what&rsquo;s working in real time.</p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/581">FireRaven Conference Hub </a></strong>went after a bigger problem: conference discovery is basically guesswork. Their platform gives speakers portable reputation profiles and lets attendees rate events across meaningful dimensions&mdash;expertise, clarity, practical impact and energy.</p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/573">Nexo</a></strong> kept it focused: tell it your role, goals and interests, and it builds you a focused conference plan with a clear explanation for every recommendation. Sometimes, the best solutions are the simple ones.</p><p><strong><a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects/580">Stage Deployer</a></strong> changes how you give talks. It lets speakers create small audience apps from a simple text prompt. Just type an idea, wait about two minutes, then share a QR code for the audience to scan. The interaction results appear live on the big screen as charts, rankings or word clouds.</p><p>We highly encourage you to <a target="_blank" href="https://www.hackathonparty.com/hackathons/43/projects">check out all the submissions in the project gallery </a>and see the incredible variety of things people built with Telerik and Kendo UI components from Progress Software.</p><p><img sf-image-responsive="true" src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/.net-maui-aiprompt/img_4975.jpeg?sfvrsn=f5e0c414_2" height="786" style="max-width:100%;height:auto;" title="IMG_4975" width="1179" alt="The Progress team in front of the booth at JS Nation / React SUmmit " sf-size="271594" /></p><p>Amsterdam delivered on all fronts: the venue was great, the crowd was friendly and the whole experience reminded us just how great it is to be able to spend time together with a bunch of folks all excited to geek out about the same stuff.</p><p><em>Huge</em> congrats to all three of our hackathon winning teams, and a massive well done to every single person who submitted. More than 30 projects in a couple of days is no joke! We had a fantastic time, and we&rsquo;re already looking forward to the next one.</p><hr /><h3>Ready to build your next React app?</h3><p><a href="https://www.telerik.com/kendo-react-ui" class="Btn" target="_blank">Explore KendoReact</a></p><img src="https://feeds.telerik.com/link/10827/17369836.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:9fd87dc0-365e-47d0-8606-b091b8bd9ccb</id>
    <title type="text">Best Practices for Exceptions in ASP.NET Core</title>
    <summary type="text">Exceptions are a common approach to dealing with unexpected situations. But are they truly necessary? Let’s see some best practices for using them in ASP.NET Core.</summary>
    <published>2026-06-29T13:01:51Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Assis Zang </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17369730/best-practices-exceptions-aspnet-core"/>
    <content type="text"><![CDATA[<p><span class="featured">Exceptions are a common approach to dealing with unexpected situations. But are they truly necessary? Let&rsquo;s see some best practices for using them in ASP.NET Core.</span></p><p>Exceptions have been part of the .NET ecosystem since the earliest versions of the .NET Framework. Today, with the platform&rsquo;s continuous evolution, their use is simpler and more integrated than ever. The problem, however, arises when they are used inappropriately or imprecisely.</p><p>In this post, we will explore in which situations the use of exceptions is truly recommended and when more appropriate alternatives should be considered. Furthermore, we will see in practice some of the most modern features available in ASP.NET Core for implementing exception handling aligned with best practices.</p><h2 id="-what-are-exceptions-in-the-context-of-asp.net-core"> What Are Exceptions in the Context of ASP.NET Core?</h2><p>In ASP.NET Core, exceptions are objects that represent unexpected events that occur during program execution and interrupt its normal flow. Common examples of flow interruption include null reference errors, invalid user input, and database connection problems.</p><p>In practice, when an exception is thrown, the .NET runtime starts looking for somewhere that knows how to handle it, typically a <code>try/catch</code> statement, as shown in the example below:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">try</span>
<span class="token punctuation">{</span>
    <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token number">10</span> <span class="token operator">/</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"Error: "</span> <span class="token operator">+</span> ex<span class="token punctuation">.</span>Message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>If this exception is not handled, it returns to the beginning of the execution and eventually reaches the ASP.NET Core pipeline, resulting in an HTTP error, usually a <code>500 - Internal Server Error</code>.</p><h2 id="-when-should-exceptions-be-avoided"> When Should Exceptions Be Avoided?</h2><p>One of the most common mistakes in backend applications is using exceptions for expected situations. If code already expects something to happen, then it&rsquo;s not exceptional, it&rsquo;s predictable.</p><p>The principle of exceptions is to <strong>reserve exceptions for unpredictable situations</strong>.</p><p>A common example of a situation where exceptions should be avoided is for input data validation. Data validation should never use exceptions as a rule. Note the example below:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>BankAccountNumber<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"BankAccountNumber is required"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>The problem here is that the system expects the client to send a user with invalid data. In other words, this is part of the normal flow, not an exception. In this case, the correct approach would be to treat this as data validation and simply return a <code>400 Bad Request</code>:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>BankAccountNumber<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">return</span> Results<span class="token punctuation">.</span><span class="token function">BadRequest</span><span class="token punctuation">(</span><span class="token string">"BankAccountNumber is required"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><h2 id="-when-does-using-exceptions-make-sense"> When Does Using Exceptions Make Sense?</h2><p>If exceptions shouldn&rsquo;t be used in the normal flow, then when do they make sense? In backend applications like ASP.NET Core, <strong>exceptions should be used when something truly unexpected happens and the application cannot continue safely or should not continue at all</strong>.</p><p>Below, we&rsquo;ll look at practical scenarios where exceptions actually make sense.</p><h3 id="-infrastructure-failures"> Infrastructure Failures</h3><p>This is a very common scenario. If the database fails here, it&rsquo;s not possible to proceed normally, meaning it&rsquo;s an exception:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">try</span>
<span class="token punctuation">{</span>
    <span class="token keyword">var</span> user <span class="token operator">=</span> <span class="token keyword">await</span> dbContext<span class="token punctuation">.</span>Users<span class="token punctuation">.</span><span class="token function">FindAsync</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> Results<span class="token punctuation">.</span><span class="token function">Ok</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">return</span> Results<span class="token punctuation">.</span><span class="token function">InternalServerError</span><span class="token punctuation">(</span>$<span class="token string">"Error retrieving user. Error details: {ex.Message}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><h3 id="⚠️-impossible-or-inconsistent-states">⚠️ Impossible or Inconsistent States</h3><p>Despite frontend and backend validations, inconsistent states can reach the application core. If this happens, something is certainly wrong, and this corrupted state cannot be saved to the database or continue its path. In this case, an exception must be generated:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">if</span> <span class="token punctuation">(</span>BankAccountNumber<span class="token punctuation">.</span>Length <span class="token operator">&lt;</span> <span class="token number">8</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidOperationException</span><span class="token punctuation">(</span><span class="token string">"The bank account number must have at least 8 digits at this point"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>If the system logic guarantees that <code>BankAccountNumber</code> will always have at least 8 characters at this point, then this indicates a bug, data inconsistency or even a flow error, and the exception is the last resort to prevent an inconsistent state at this stage of the process.</p><h3 id="-dependency-on-external-services"> Dependency on External Services</h3><p>If the external service is mandatory for the flow and the absence of data completely prevents correct processing, then you are dealing with a real error and the exception represents a technical problem.</p><p>In this case, it is correct to throw an exception because the process cannot continue with inconsistent data. Furthermore, it is important to clarify that the error occurred in the integration between the services, as demonstrated in the example below:</p><pre class=" language-csharp"><code class="prism  language-csharp">   <span class="token keyword">var</span> customer <span class="token operator">=</span> <span class="token keyword">await</span> externalService<span class="token punctuation">.</span><span class="token function">GetCustomerAsync</span><span class="token punctuation">(</span>customerId<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>customer <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidOperationException</span><span class="token punctuation">(</span><span class="token string">"Unable to retrieve customer data from the external service: CustomerService"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
</code></pre><h2 id="result-pattern-as-an-alternative">Result Pattern as an Alternative</h2><p>If exceptions shouldn&rsquo;t be used for normal flow, the question arises: what would be a good alternative to represent expected errors?</p><p>One of the most widely used alternatives today is the Result Pattern. The Result Pattern is a design pattern used to manage execution flow and errors, returning a structured object instead of throwing exceptions for expected failures.</p><p>Instead of throwing exceptions, the method returns an object indicating whether it succeeded or failed and why.</p><h3 id="implementing-the-result-pattern">Implementing the Result Pattern</h3><p>To use the Result Pattern, we will create a simple application and then create the classes and methods. The complete source code with examples is available in this GitHub repository: <a target="_blank" href="https://github.com/zangassis/practicing-exception-handling">PracticingExceptionHandling source code</a>.</p><p>To create the base, you can use the command below in your terminal:</p><pre class=" language-bash"><code class="prism  language-bash">dotnet new web -o PracticingExceptionHandling
</code></pre><p>Open the application and create the following class within it:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">namespace</span> PracticingExceptionHandling<span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Result</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">bool</span> IsSuccess <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token keyword">public</span> <span class="token keyword">string</span> Error <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token keyword">protected</span> <span class="token function">Result</span><span class="token punctuation">(</span><span class="token keyword">bool</span> isSuccess<span class="token punctuation">,</span> <span class="token keyword">string</span> error<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        IsSuccess <span class="token operator">=</span> isSuccess<span class="token punctuation">;</span>
        Error <span class="token operator">=</span> error<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> Result <span class="token function">Ok</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">new</span> <span class="token class-name">Result</span><span class="token punctuation">(</span><span class="token keyword">true</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> Result <span class="token function">Fail</span><span class="token punctuation">(</span><span class="token keyword">string</span> error<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">new</span> <span class="token class-name">Result</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span> <span class="token punctuation">:</span> Result
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> T Value <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token function">Result</span><span class="token punctuation">(</span>T <span class="token keyword">value</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">base</span><span class="token punctuation">(</span><span class="token keyword">true</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        Value <span class="token operator">=</span> <span class="token keyword">value</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token function">Result</span><span class="token punctuation">(</span><span class="token keyword">string</span> error<span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">base</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> Result<span class="token operator">&lt;</span>T<span class="token operator">&gt;</span> <span class="token function">Ok</span><span class="token punctuation">(</span>T <span class="token keyword">value</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">new</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">new</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span> <span class="token function">Fail</span><span class="token punctuation">(</span><span class="token keyword">string</span> error<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token keyword">new</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Note that two <code>Result</code> classes are implemented, both aiming to explicitly represent the success or failure of an operation as well as the error details. The base class defines the common structure for any result. It has the <code>IsSuccess</code> property, which indicates whether the operation was successful, and the <code>Error</code> property, which contains the error message in case of failure.</p><p>The generic <code>Result&lt;T&gt;</code> class extends this idea to operations that return a value. When the operation is successful, in addition to <code>IsSuccess</code> being true, the result also carries a <code>Value</code> of type <code>T</code>. For this, there are two distinct private constructors: one for success, which receives the value, and another for failure, which receives only the error message. This avoids the creation of invalid states within the class itself.</p><p>The static methods <code>Ok</code> and <code>Fail</code> in the generic version follow the same pattern as the base class, but now allow data to be returned along with the result. This is useful in scenarios such as searches, validations or external integrations, where you want to return a value on success or a clear explanation on error, without throwing exceptions for expected situations.</p><p>An important point is that the consumer of the result must always check <code>IsSuccess</code> before accessing <code>Value</code>. This is a desirable behavior, as it forces the API user to explicitly handle failures, preventing silent errors or unexpected flows.</p><p>Now create a new class called <code>UserService</code> and add the following code to it:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">namespace</span> PracticingExceptionHandling<span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserService</span>
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> Result<span class="token operator">&lt;</span>User<span class="token operator">&gt;</span> <span class="token function">CreateUser</span><span class="token punctuation">(</span>User newUser<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>newUser<span class="token punctuation">.</span>Name<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token keyword">return</span> Result<span class="token operator">&lt;</span>User<span class="token operator">&gt;</span><span class="token punctuation">.</span><span class="token function">Fail</span><span class="token punctuation">(</span><span class="token string">"Name is required"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">var</span> user <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">User</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            Id <span class="token operator">=</span> newUser<span class="token punctuation">.</span>Id<span class="token punctuation">,</span>
            Name <span class="token operator">=</span> newUser<span class="token punctuation">.</span>Name<span class="token punctuation">,</span>
            BankAccountNumber <span class="token operator">=</span> newUser<span class="token punctuation">.</span>BankAccountNumber<span class="token punctuation">,</span>
            Status <span class="token operator">=</span> <span class="token number">1</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> Result<span class="token operator">&lt;</span>User<span class="token operator">&gt;</span><span class="token punctuation">.</span><span class="token function">Ok</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Here we have the <code>CreateUser</code> method which validates whether the <code>Name</code> property is null or contains only spaces. If either of these conditions is true, the method immediately returns a failure result <code>Result&lt;User&gt;.Fail</code>, preventing the creation of an invalid user and explicitly stating the reason for the error.</p><p>If the validation passes, a new <code>User</code> object is instantiated with the data provided in the request, also applying a default value for <code>Status</code>. Finally, the method returns a success result <code>Result&lt;User&gt;.Ok</code>, encapsulating the created object.</p><p>The next step is to call the <code>CreateUser</code> method, so in the <code>Program</code> class, add the following endpoint:</p><pre class=" language-csharp"><code class="prism  language-csharp">app<span class="token punctuation">.</span><span class="token function">MapPost</span><span class="token punctuation">(</span><span class="token string">"/users/create"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>User newUser<span class="token punctuation">,</span> UserService userService<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span>
<span class="token punctuation">{</span>
    <span class="token keyword">var</span> result <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">CreateUser</span><span class="token punctuation">(</span>newUser<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>result<span class="token punctuation">.</span>IsSuccess<span class="token punctuation">)</span>
        <span class="token keyword">return</span> Results<span class="token punctuation">.</span><span class="token function">BadRequest</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token punctuation">{</span> error <span class="token operator">=</span> result<span class="token punctuation">.</span>Error <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> Results<span class="token punctuation">.</span><span class="token function">Ok</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>Value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In this endpoint, we define a POST route <code>/users/create</code> that receives a User object and a <code>UserService</code> instance. Upon receiving the request, the endpoint calls the <code>CreateUser</code> method, which returns a <code>Result&lt;User&gt;</code>. This return encapsulates both success and potential failure.</p><p>Next, the endpoint checks the <code>IsSuccess</code> property. If the result indicates failure, it returns a <code>400 Bad Request</code>, including the error message (<code>result.Error</code>) in the response body, clearly explaining the reason for the rejection to the client. If the operation is successful, the endpoint returns a <code>200 OK</code> with the created object (<code>result.Value</code>).</p><p>In this way, we use the Result Pattern as a clear contract between the layers, which improves the readability and predictability of the API&rsquo;s behavior, reserving exceptions only for unpredictable scenarios.</p><h2 id="✨-expressive-exceptions">✨ Expressive Exceptions</h2><p>A common mistake when using exceptions is creating weak or generic exceptions. We&rsquo;ve already seen that exceptions should be reserved for unpredictable errors; in this case, when an error occurs, it&rsquo;s important to obtain as much information as possible about why that exception happened. Consider the example below:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"User not found"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The problem here is that the system knows something went wrong but doesn&rsquo;t know exactly what went wrong (that is, the reason for the error).</p><p>To solve this, we can create a custom exception. Custom exceptions are classes that represent domain or application specific errors. Consider the following example:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserNotFoundException</span> <span class="token punctuation">:</span> Exception
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token function">UserNotFoundException</span><span class="token punctuation">(</span><span class="token keyword">string</span> id<span class="token punctuation">)</span>
        <span class="token punctuation">:</span> <span class="token keyword">base</span><span class="token punctuation">(</span>$<span class="token string">"User with id {id} was not found"</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Now the error has an identity. It provides user details and makes it explicit that this is a domain exception and is important to the application, much more explicit than a generic exception.</p><p>Now see how it looks in the call:</p><p><strong>❌ Generic</strong></p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"User not found"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><strong>✅ Specific (Custom Exception)</strong></p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">UserNotFoundException</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>With custom exceptions, we obtain better tracking (logs), the possibility of specific handling and more expressive code.</p><h2 id="-creating-exceptions-with-helper-methods"> Creating Exceptions with Helper Methods</h2><p>When using custom exceptions, it&rsquo;s common to have duplicate exceptions, for example, when the same exception is thrown in multiple parts of the class. Note the example below:</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token keyword">public</span> <span class="token function">User</span><span class="token punctuation">(</span><span class="token keyword">string</span> name<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidUserException</span><span class="token punctuation">(</span><span class="token string">"Name cannot be empty"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    Name <span class="token operator">=</span> name<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">UpdateName</span><span class="token punctuation">(</span><span class="token keyword">string</span> name<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidUserException</span><span class="token punctuation">(</span><span class="token string">"Name cannot be empty"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    Name <span class="token operator">=</span> name<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>In both cases, the same exception is being thrown, using the same details. To reuse exceptions, we can create helper methods and even generic methods depending on the context in which they are used. In the case above, we can create a method that expects the name of a property and returns a custom exception and use it everywhere it is useful:</p><pre class=" language-csharp"><code class="prism  language-csharp">   <span class="token keyword">public</span> <span class="token function">User</span><span class="token punctuation">(</span><span class="token keyword">string</span> name<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token keyword">throw</span> <span class="token function">NewInvalidPropertyException</span><span class="token punctuation">(</span><span class="token string">"Name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        Name <span class="token operator">=</span> name<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">UpdateName</span><span class="token punctuation">(</span><span class="token keyword">string</span> name<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token keyword">throw</span> <span class="token function">NewInvalidPropertyException</span><span class="token punctuation">(</span><span class="token string">"Name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        Name <span class="token operator">=</span> name<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> InvalidUserException <span class="token function">NewInvalidPropertyException</span><span class="token punctuation">(</span><span class="token keyword">string</span> property<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">InvalidUserException</span><span class="token punctuation">(</span>$<span class="token string">"{property} cannot be empty"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
</code></pre><h2 id="-conclusion"> Conclusion</h2><p>Exceptions are an excellent feature of ASP.NET Core and are especially useful in unpredictable scenarios or as a last line of defense to prevent invalid states from progressing through the flow or persisting in the database. The problem arises when they are used to handle expected errors or in a generic way, without providing sufficient details.</p><p>In this post, we explore best practices in the use of exceptions and examine the Result Pattern as a more suitable alternative for predictable scenarios.</p><p>I hope this post helps you make better decisions when using exceptions, when to avoid them and how to apply them effectively in your applications.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Exploring the SLNX Solution File Format</h4></div><div class="col-8"><p class="u-fs16 u-mb0">If you&rsquo;ve worked with .NET for any length of time, you&rsquo;ve made peace with the .sln file. But as of .NET 10, we&rsquo;ve got .slnx. <a target="_blank" href="https://www.telerik.com/blogs/exploring-slnx-solution-file-format">Let&rsquo;s talk about what .slnx is</a>, why it exists, what it gets right and where you might get tripped up.</p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17369730.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:0d4c4648-b7a2-4e28-9530-a66dd91961b4</id>
    <title type="text">REST to tRPC Migration in NestJS Monorepos</title>
    <summary type="text">Convert a shared monorepo with a NestJS REST API and Next.js to tRPC. Replace NestJS controllers with typed tRPC routers that expose procedures instead of endpoints, updating the frontend to consume those procedures with fully typed hooks and no manual type definitions.</summary>
    <published>2026-06-26T15:33:25Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Christian Nwamba </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17368678/rest-trpc-migration-nestjs-monorepos"/>
    <content type="text"><![CDATA[<p><span class="featured">Convert a shared monorepo with a NestJS REST API and Next.js to tRPC. Replace NestJS controllers with typed tRPC routers that expose procedures instead of endpoints, updating the frontend to consume those procedures with fully typed hooks and no manual type definitions.</span></p><p>This post covers how to convert a shared monorepo with a <a target="_blank" href="https://nestjs.com/">NestJS</a> REST API and <a target="_blank" href="https://nextjs.org/">Next.js</a> to <a target="_blank" href="https://trpc.io/">tRPC</a>.</p><p>We&rsquo;ll replace NestJS controllers with typed tRPC routers that expose procedures instead of endpoints, and update our frontend to consume those procedures with fully typed hooks and no manual type definitions. By the end, you&rsquo;ll learn how to prevent backend-to-frontend API mismatches at compile time rather than in production.</p><h2 id="prerequisites">Prerequisites</h2><ul><li>Basic knowledge of <a target="_blank" href="https://nestjs.com/">NestJS</a> and <a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a></li><li>Familiarity with REST APIs and how HTTP requests work</li><li>Node.js and pnpm installed</li><li>Basic knowledge of <a target="_blank" href="https://nextjs.org/">Next.js</a></li></ul><h2 id="why-choose-trpc-over-rest">Why Choose tRPC Over REST</h2><p>In a REST setup, you have type safety on the server and on the client, but there&rsquo;s a blind spot at the boundary between them. In a REST API, when the client fetches data, it has to manually define the response type. This is typically done by copying API specifications from the backend. However, because these definitions are copies, if changes are made on the backend without updating the client, no problems are noticed immediately, the builds still pass, but users encounter errors in production.</p><p>tRPC solves this by sharing the router type directly from the server to the client. The client uses the same type definitions as the backend. <a target="_blank" href="https://nestjs-trpc.io/">nestjs-trpc</a> creates the AppRouter type using our <a target="_blank" href="https://zod.dev/">Zod</a> output schemas, and the client imports this type directly.</p><p>If the backend changes, the type changes, and TypeScript immediately flags the call sites.</p><h2 id="project-setup">Project Setup</h2><p>This guide assumes you already have a NestJS REST API and a Next.js app running together in a pnpm monorepo. If you need a starting point, you can <a target="_blank" href="https://github.com/christiannwamba/trpc-starter">clone the starter repo here</a> and run the install command at the root:</p><pre class=" language-shell"><code class="prism  language-shell">pnpm install
</code></pre><p>We will be migrating the NestJS backend from REST to tRPC and updating the frontend to consume it with typed hooks. Here is what the structure will look like at the end:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/project-structure-diagram.png?sfvrsn=ddad2fc6_2" title="Project structure diagram" alt="Project structure diagram" /></p><h2 id="monorepo-foundation">Monorepo Foundation</h2><p>Since you already have a pnpm monorepo set up, there are just two things to add before we start the migration.</p><p>First, add the <code>@api/*</code> path alias to the existing <code>tsconfig.base.json</code> file:</p><pre class=" language-js"><code class="prism  language-js"><span class="token punctuation">{</span>
  <span class="token string">"compilerOptions"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"baseUrl"</span><span class="token punctuation">:</span> <span class="token string">"."</span><span class="token punctuation">,</span>
    <span class="token string">"paths"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"@api/*"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"apps/server/src/*"</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>This alias allows the frontend to import types directly from the backend source without having to create and publish a package for sharing types.</p><p>Next, let&rsquo;s add scripts to our root <code>package.json</code> file so we can run commands more conveniently:</p><pre class=" language-js"><code class="prism  language-js"><span class="token punctuation">{</span>
<span class="token string">"scripts"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"types:generate"</span><span class="token punctuation">:</span> <span class="token string">"pnpm --filter server exec nestjs-trpc generate --entrypoint src/app.module.ts"</span><span class="token punctuation">,</span>
    <span class="token string">"typecheck:web"</span><span class="token punctuation">:</span> <span class="token string">"pnpm --filter web run typecheck"</span><span class="token punctuation">,</span>
    <span class="token string">"verify:types"</span><span class="token punctuation">:</span> <span class="token string">"pnpm run types:generate &amp;&amp; pnpm run typecheck:web"</span><span class="token punctuation">,</span>
    <span class="token string">"dev:server"</span><span class="token punctuation">:</span> <span class="token string">"pnpm --filter server run start:dev"</span><span class="token punctuation">,</span>
    <span class="token string">"dev:web"</span><span class="token punctuation">:</span> <span class="token string">"pnpm --filter web run dev"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the snippet above, <code>types:generate</code> runs the nestjs-trpc CLI to create the AppRouter type using our backend routers. <code>typecheck:web</code> runs <code>tsc --noEmit</code> on the Next.js app. <code>verify:types</code> combines both of them. We&rsquo;ll use these scripts in the type safety section. <code>dev:server</code> and <code>dev:web</code> are used to start the server and frontend, respectively.</p><h2 id="backend-setup">Backend Setup</h2><p>Run the command below to install the dependencies we&rsquo;ll need for this project:</p><pre class=" language-shell"><code class="prism  language-shell">cd apps/server
pnpm add nestjs-trpc @trpc/server zod superjson express
pnpm add -D @types/express
</code></pre><p>In the snippet above:</p><ul><li><strong>nestjs-trpc:</strong> Integrates tRPC into NestJS&rsquo;s module and DI system</li><li><strong>@trpc/server:</strong> The core tRPC server library</li><li><strong>zod:</strong> Handles input and output schema validation for each procedure</li><li><strong>superjson:</strong> The serializer that handles data types JSON can&rsquo;t handle natively, like dates, maps and sets</li><li><strong>express and @types/express:</strong> Used to properly type the request and response objects from <a target="_blank" href="https://expressjs.com/">Express</a></li></ul><p>Next, update your <code>app.module.ts</code> file with the following:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Module <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@nestjs/common'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> TRPCModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'nestjs-trpc'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> superjson <span class="token keyword">from</span> <span class="token string">'superjson'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> AppContext <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./trpc/app.context'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> ProtectedMiddleware <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./trpc/protected.middleware'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> UsersModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./users/users.module'</span><span class="token punctuation">;</span>

@<span class="token function">Module</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    TRPCModule<span class="token punctuation">.</span><span class="token function">forRoot</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      context<span class="token punctuation">:</span> AppContext<span class="token punctuation">,</span>
      transformer<span class="token punctuation">:</span> superjson<span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    UsersModule<span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span>AppContext<span class="token punctuation">,</span> ProtectedMiddleware<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AppModule</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p>In the code snippet above, <code>TRPCModule.forRoot</code> wires tRPC into NestJS. The <code>context</code> option points to the class responsible for building the per-request context object, which is <code>AppContext</code> (we&rsquo;ll build this in the next section). The transformer option handles serialization: <code>superjson</code> extends JSON to correctly handle dates, maps, sets and undefined values across the wire. <code>UsersModule</code> is imported just as it would be in a REST app, we&rsquo;re still using the standard NestJS module structure.</p><p>Next, let&rsquo;s create a <code>src/trpc/app.context.ts</code> file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@nestjs/common'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> CreateExpressContextOptions <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@trpc/server/adapters/express'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">type</span> AppRequestContext <span class="token operator">=</span> <span class="token punctuation">{</span>
  req<span class="token punctuation">:</span> CreateExpressContextOptions<span class="token punctuation">[</span><span class="token string">'req'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  res<span class="token punctuation">:</span> CreateExpressContextOptions<span class="token punctuation">[</span><span class="token string">'res'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AppContext</span> <span class="token punctuation">{</span>
  <span class="token keyword">async</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    req<span class="token punctuation">,</span>
    res<span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">:</span> CreateExpressContextOptions<span class="token punctuation">)</span><span class="token punctuation">:</span> Promise<span class="token operator">&lt;</span>AppRequestContext<span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span> req<span class="token punctuation">,</span> res <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>While in REST NestJS the request is readily available via the <code>@Req decorator</code> or <code>guards</code>, in tRPC, context is the mechanism that carries per-request data, the raw request, the current user or anything a procedure might need. Procedures are individual callable endpoints defined inside a router (e.g., getUser and createUser in UsersRouter).</p><p><code>AppRequestContext</code> defines the shape of the context object that each procedure will receive. It has req and res, which are typed using <code>CreateExpressContextOptions</code>, which is a type that gives us the raw Express <code>req</code> and <code>res</code> objects from the incoming HTTP request.</p><p>The <code>create</code> method is called automatically by <code>nestjs-trpc</code> on every incoming request, and its return value becomes the <code>context</code> object. Notice it&rsquo;s only returning <code>req</code> and <code>res</code>. This is intentional, because context isn&rsquo;t where we guard the endpoints, but where we make the request data available to the middleware that will do the guarding. We&rsquo;ll show how this works in <code>ProtectedMiddleware</code>.</p><p>The flow is: <code>AppContext</code> creates the context, <code>ProtectedMiddleware</code> inspects it, and <code>procedures</code> run if the middleware allows them through.</p><h2 id="creating-our-router">Creating Our Router</h2><p>Next, a new file s<code>rc/users/users.schema.ts</code> and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'zod'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> userNameSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> getUserOutputSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  name<span class="token punctuation">:</span> userNameSchema<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> createUserOutputSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  id<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  username<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  email<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">type</span> GetUserOutput <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&lt;</span><span class="token keyword">typeof</span> getUserOutputSchema<span class="token operator">&gt;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">type</span> CreateUserOutput <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&lt;</span><span class="token keyword">typeof</span> createUserOutputSchema<span class="token operator">&gt;</span><span class="token punctuation">;</span>
</code></pre><p>These schemas serve two purposes: runtime validation via Zod and type generation via the nestjs-trpc CLI. The output schemas are what the frontend&rsquo;s AppRouter types will be derived from after we run <code>types:generate</code>.</p><p>Next, update the <code>src/users/users.service.ts</code> file with the following:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@nestjs/common'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> CreateUserOutput<span class="token punctuation">,</span> GetUserOutput <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./users.schema'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">type</span> CreateUserInput <span class="token operator">=</span> <span class="token punctuation">{</span> username<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span> email<span class="token punctuation">:</span> <span class="token keyword">string</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">UsersService</span> <span class="token punctuation">{</span>
  <span class="token function">findById</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span><span class="token punctuation">:</span> GetUserOutput <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span> id<span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">'John Doe'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token function">create</span><span class="token punctuation">(</span>data<span class="token punctuation">:</span> CreateUserInput<span class="token punctuation">)</span><span class="token punctuation">:</span> CreateUserOutput <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span> <span class="token operator">...</span>data <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Our user service remains relatively unchanged. The business logic layer doesn&rsquo;t care whether it&rsquo;s being called by a REST controller or a tRPC router. We keep the same layered architecture we&rsquo;re used to in NestJS.</p><p>Create <code>src/users/users.router.ts</code> file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Router<span class="token punctuation">,</span> Query<span class="token punctuation">,</span> Mutation<span class="token punctuation">,</span> Input<span class="token punctuation">,</span> UseMiddlewares <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'nestjs-trpc'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'zod'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> ProtectedMiddleware <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../trpc/protected.middleware'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> UsersService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./users.service'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> createUserOutputSchema<span class="token punctuation">,</span> getUserOutputSchema <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./users.schema'</span><span class="token punctuation">;</span>

@<span class="token function">Router</span><span class="token punctuation">(</span><span class="token punctuation">{</span> alias<span class="token punctuation">:</span> <span class="token string">'users'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">UsersRouter</span> <span class="token punctuation">{</span>
  <span class="token keyword">constructor</span><span class="token punctuation">(</span><span class="token keyword">private</span> readonly usersService<span class="token punctuation">:</span> UsersService<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

  @<span class="token function">Query</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    input<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    output<span class="token punctuation">:</span> getUserOutputSchema<span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token function">getUser</span><span class="token punctuation">(</span>@<span class="token function">Input</span><span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span> id<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>usersService<span class="token punctuation">.</span><span class="token function">findById</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  @<span class="token function">Mutation</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    input<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      username<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      email<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    output<span class="token punctuation">:</span> createUserOutputSchema<span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  @<span class="token function">UseMiddlewares</span><span class="token punctuation">(</span>ProtectedMiddleware<span class="token punctuation">)</span>
  <span class="token function">createUser</span><span class="token punctuation">(</span>@<span class="token function">Input</span><span class="token punctuation">(</span><span class="token punctuation">)</span> data<span class="token punctuation">:</span> <span class="token punctuation">{</span> username<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span> email<span class="token punctuation">:</span> <span class="token keyword">string</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>usersService<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In a regular REST controller, we&rsquo;d have <code>@Get('id')</code>. But in tRPC, we have <code>@Query</code>, and <code>@Post()</code> becomes <code>@Mutation()</code>.</p><p>Although the decorators look similar, the difference is in the input and output Zod schemas attached to each procedure. We use the input schema for validation, so the procedure only receives data in the exact shape it expects. The output schema determines the shape that the frontend will expect for the response body. <code>@UseMiddlewares(ProtectedMiddleware)</code> is a per-procedure guard applied to <code>createUser</code>. We&rsquo;ll discuss this next.</p><p>Update your <code>src/users/users.module.ts</code> file to register the router and export the service:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Module <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@nestjs/common'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> UsersRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./users.router'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> UsersService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./users.service'</span><span class="token punctuation">;</span>

@<span class="token function">Module</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span>UsersRouter<span class="token punctuation">,</span> UsersService<span class="token punctuation">]</span><span class="token punctuation">,</span>
  exports<span class="token punctuation">:</span> <span class="token punctuation">[</span>UsersService<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">UsersModule</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p><code>UsersRouter</code> and <code>UsersService</code> are registered as providers above. <code>nestjs-trpc</code> discovers <code>UsersRouter</code> automatically because it&rsquo;s decorated with <code>@Router</code>. Every module registers its routers in this same way.</p><p>We can now delete <code>users.controller.ts</code>, as it&rsquo;s no longer being referenced.</p><h2 id="protected-procedures">Protected Procedures</h2><p>Just like guards, we can add protection to an individual procedure or to the router as a whole.</p><p>Create a <code>src/trpc/protected.middleware.ts</code> file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@nestjs/common'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> TRPCError <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@trpc/server'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> Request <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'express'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> MiddlewareOptions<span class="token punctuation">,</span> TRPCMiddleware <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'nestjs-trpc'</span><span class="token punctuation">;</span>

<span class="token keyword">type</span> AuthUser <span class="token operator">=</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token keyword">string</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">parseBearerToken</span><span class="token punctuation">(</span>header<span class="token punctuation">:</span> <span class="token keyword">string</span> <span class="token operator">|</span> undefined<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">string</span> <span class="token operator">|</span> <span class="token keyword">null</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>header<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">'Bearer '</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> token <span class="token operator">=</span> header<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token string">'Bearer '</span><span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> token<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">?</span> token <span class="token punctuation">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ProtectedMiddleware</span> <span class="token keyword">implements</span> <span class="token class-name">TRPCMiddleware</span> <span class="token punctuation">{</span>
  <span class="token keyword">async</span> <span class="token function">use</span><span class="token punctuation">(</span>opts<span class="token punctuation">:</span> MiddlewareOptions<span class="token operator">&lt;</span>object<span class="token punctuation">,</span> Record<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> unknown<span class="token operator">&gt;&gt;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token punctuation">{</span> ctx<span class="token punctuation">,</span> next <span class="token punctuation">}</span> <span class="token operator">=</span> opts<span class="token punctuation">;</span>
    <span class="token keyword">const</span> req <span class="token operator">=</span> <span class="token punctuation">(</span>ctx <span class="token keyword">as</span> <span class="token punctuation">{</span> req<span class="token operator">?</span><span class="token punctuation">:</span> Request <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>req<span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>req<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">TRPCError</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        code<span class="token punctuation">:</span> <span class="token string">'INTERNAL_SERVER_ERROR'</span><span class="token punctuation">,</span>
        message<span class="token punctuation">:</span> <span class="token string">'Request missing from context.'</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">const</span> token <span class="token operator">=</span> <span class="token function">parseBearerToken</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>headers<span class="token punctuation">.</span>authorization<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">!==</span> <span class="token string">'demo-token'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">TRPCError</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        code<span class="token punctuation">:</span> <span class="token string">'UNAUTHORIZED'</span><span class="token punctuation">,</span>
        message<span class="token punctuation">:</span> <span class="token string">'Authentication required.'</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">const</span> user<span class="token punctuation">:</span> AuthUser <span class="token operator">=</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token string">'1'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">{</span> ctx<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span>ctx<span class="token punctuation">,</span> user <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, <code>ProtectedMiddleware</code> is a class that implements <code>TRPCMiddleware</code>, and gives it a <code>use</code> method that runs automatically before any procedure it&rsquo;s applied to.</p><p><code>MiddlewareOptions</code> gives us <code>ctx</code> (the context object from AppContext) and <code>next</code> (which we call to pass control to the procedure). <code>parseBearerToken</code> pulls the token from the Authorization header. If the token check fails, a <code>TRPCError</code> with code <code>UNAUTHORIZED</code> is thrown and the procedure doesn&rsquo;t run. If it passes, we call <code>next()</code> with an enriched context that now includes the user.</p><p>That user object is now accessible inside the procedure through <code>ctx</code>, which is the same concept as <code>req.user</code> in a NestJS Guard.</p><h2 id="generating-the-approuter">Generating the AppRouter</h2><p>With our router and output schemas in place, run the CLI generator from the monorepo root:</p><pre class=" language-shell"><code class="prism  language-shell">npm run types:generate
</code></pre><p>This produces <code>apps/server/src/@generated/server.ts</code>, a file that contains the <code>AppRouter</code> type derived from our routers and Zod schemas. Do not manually edit this file, as it will be overwritten on every generation.</p><p>Next, create <code>src/trpc/schema.ts</code> to use as the stable re-export path for clients:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> AppRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../@generated/server'</span><span class="token punctuation">;</span>
</code></pre><h2 id="frontend-setup">Frontend Setup</h2><p>Let&rsquo;s install the dependencies we&rsquo;ll need for this project:</p><pre class=" language-shell"><code class="prism  language-shell">cd apps/web
pnpm add @trpc/client @trpc/server @trpc/react-query @tanstack/react-query superjson
</code></pre><p>Now, update your <code>tsconfig.json</code> file to add the <code>@api/*</code> path alias pointing to the server source, extend the base config, and set baseUrl to <code>.</code> so the path aliases resolve correctly. Merge this with your existing <code>tsconfig.json</code> instead of replacing it:</p><pre class=" language-js"><code class="prism  language-js"><span class="token punctuation">{</span>
  <span class="token string">"extends"</span><span class="token punctuation">:</span> <span class="token string">"../../tsconfig.base.json"</span><span class="token punctuation">,</span>
  <span class="token string">"compilerOptions"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"baseUrl"</span><span class="token punctuation">:</span> <span class="token string">"."</span><span class="token punctuation">,</span>
    <span class="token string">"paths"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"@/*"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"./src/*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token string">"@api/*"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"../server/src/*"</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Next, create a <code>src/utils/trpc.ts</code> file and add the following to it:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token string">'use client'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> createTRPCReact <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@trpc/react-query'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> AppRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@api/trpc/schema'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> trpc <span class="token operator">=</span> createTRPCReact<span class="token operator">&lt;</span>AppRouter<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the code above, the <code>AppRouter</code> type import from <code>@api/trpc/schema</code> connects the frontend to the backend&rsquo;s type definitions. Every hook we call using trpc will have its input and output types pulled directly from the backend router.</p><p>Next, create a <code>src/app/providers.tsx</code> file and add the following to it:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token string">'use client'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> QueryClient<span class="token punctuation">,</span> QueryClientProvider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@tanstack/react-query'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> httpBatchLink <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@trpc/client'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> superjson <span class="token keyword">from</span> <span class="token string">'superjson'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> trpc <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@/utils/trpc'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">Providers</span><span class="token punctuation">(</span><span class="token punctuation">{</span> children <span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> children<span class="token punctuation">:</span> React<span class="token punctuation">.</span>ReactNode <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>queryClient<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">new</span> <span class="token class-name">QueryClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>trpcClient<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
    trpc<span class="token punctuation">.</span><span class="token function">createClient</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      links<span class="token punctuation">:</span> <span class="token punctuation">[</span>
        <span class="token function">httpBatchLink</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
          url<span class="token punctuation">:</span> <span class="token string">'http://localhost:3000/trpc'</span><span class="token punctuation">,</span>
          transformer<span class="token punctuation">:</span> superjson<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>trpc.Provider</span> <span class="token attr-name">client</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>trpcClient<span class="token punctuation">}</span></span> <span class="token attr-name">queryClient</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>queryClient<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>QueryClientProvider</span> <span class="token attr-name">client</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>queryClient<span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>children<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>QueryClientProvider</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>trpc.Provider</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, <code>Providers</code> sets up a React Query <code>QueryClient</code> for caching and a tRPC client configured with <code>httpBatchLink</code>, which points to the NestJS server and uses <code>superjson</code> for serialization. This matches the transformer we set on the backend.</p><p>Both clients are initialized with <code>useState</code> so they&rsquo;re created once per render tree. To make tRPC hooks available throughout our app, we wrap the root layout with <code>Providers</code>.</p><p>Update the <code>src/app/layout.tsx</code> to wrap children with Providers:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token keyword">import</span> type <span class="token punctuation">{</span> Metadata <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'next'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Providers <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./providers'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> metadata<span class="token punctuation">:</span> Metadata <span class="token operator">=</span> <span class="token punctuation">{</span>
  title<span class="token punctuation">:</span> <span class="token string">'NestJS tRPC Migration'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">RootLayout</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  children<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
  children<span class="token punctuation">:</span> React<span class="token punctuation">.</span>ReactNode<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Providers</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>children<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Providers</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Let&rsquo;s now update the <code>src/app/page.tsx</code> to consume the tRPC query:</p><pre class=" language-jsx"><code class="prism  language-jsx"><span class="token string">'use client'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> trpc <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@/utils/trpc'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Home</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> data<span class="token punctuation">,</span> isLoading <span class="token punctuation">}</span> <span class="token operator">=</span> trpc<span class="token punctuation">.</span>users<span class="token punctuation">.</span>getUser<span class="token punctuation">.</span><span class="token function">useQuery</span><span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token string">'1'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>isLoading<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>Loading<span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">style</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> padding<span class="token punctuation">:</span> <span class="token string">'2rem'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">{</span>data<span class="token operator">?</span><span class="token punctuation">.</span>name <span class="token operator">?</span><span class="token operator">?</span> <span class="token string">''</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Compared to REST, there&rsquo;s no manual <code>User</code> type definition and no risk of backend mismatches. If the <code>name</code> field doesn&rsquo;t exist on the output schema, TypeScript tells us immediately.</p><h2 id="proving-end-to-end-type-safety">Proving End-To-End Type Safety</h2><p>To test, we&rsquo;ll make a change to the backend definition and see if TypeScript flags the call site. In your <code>users.schema.ts</code> file, change <code>userNameSchema</code> from a plain string to a structured object:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token comment">// Before</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> userNameSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// After</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> userNameSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  firstName<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  lastName<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Then, from the monorepo root, regenerate and typecheck:</p><pre class=" language-shell"><code class="prism  language-shell">npm run types:generate
npm run typecheck:web
</code></pre><p>Without touching the <code>page.tsx</code>, TypeScript will error. <code>data?.name</code> in <code>page.tsx</code> is no longer a string, it&rsquo;s <code>{ firstName: string; lastName: string }</code>, and TypeScript will flag every call site that references the old shape.</p><h2 id="conclusion">Conclusion</h2><p>In this post, we migrated a NestJS REST API to tRPC. Controllers were replaced with typed routers, we handled auth with middleware, and wired up our Next.js frontend to share types directly with the backend. With this setup, we&rsquo;ve learned how to reliably prevent backend-to-frontend API mismatches.</p><p>Possible next steps you can take include adding more routers, chaining <code>verify:types</code> with <code>nest build</code> and <code>next build</code> into a single pre-merge script, or using tRPC subscriptions.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Deploying Containerized NestJS Applications on GCP Using Cloud Run</h4></div><div class="col-8"><p class="u-fs16 u-mb0">While there are numerous ways to deploy an app to Cloud Run, see <a target="_blank" href="https://www.telerik.com/blogs/deploying-containerized-nestjs-applications-gcp-using-cloud-run">how to containerize and deploy a NestJS API</a>. We will use a few products on GCP, such as Buildpacks and Artifact Registry, to build and deploy our image, and then finally deploy it to Cloud Run.</p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17368678.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:f453a1a3-be23-4d75-bf04-ef6ba83b2753</id>
    <title type="text">Blazor Basics: Implementing a Loading Indicator for Asynchronous Components</title>
    <summary type="text">Learn how to properly implement a custom loading indicator and why professional UI libraries can provide the best user experience.</summary>
    <published>2026-06-24T19:22:32Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Claudio Bernasconi </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17367500/blazor-basics-implementing-loading-indicator-asynchronous-components"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to properly implement a custom loading indicator and why professional UI libraries can provide the best user experience.</span></p><p>In modern web development, we often asynchronously load data from the server. Blazor is no different. To let the user know that data is being loaded and the app is working, we should show a busy or loading indicator during such operations.</p><p>In this article, we will implement a basic loading indicator in Blazor using CSS and also explore more advanced solutions.</p><p>You can <a target="_blank" href="https://github.com/claudiobernasconi/BlazorLoadingIndicator">access the code used in this example on GitHub</a>.</p><h2 id="the-blazor-project-template-approach">The Blazor Project Template Approach</h2><p>Let&rsquo;s start simple by looking at the loading indicator used in the default Blazor project template.</p><pre class=" language-html"><code class="prism  language-html">@if (forecasts == null)
{
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>em</span><span class="token punctuation">&gt;</span></span>Loading...<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>em</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
}
else
{
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>table<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- code omitted --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>table</span><span class="token punctuation">&gt;</span></span>
}
</code></pre><p>This very basic approach uses an <code>if-else</code> statement to determine the component state and a simple paragraph HTML element to render a <em>&ldquo;Loading&hellip;&rdquo;</em> text.</p><p>There are a few flaws with this overly simplistic solution:</p><ol><li><p>Static text does not provide a modern user experience. In a world where attention spans are short and user experience is important, we should use a <strong>spinner animation</strong> or another element that conveys the <strong>feeling of progress</strong>.</p></li><li><p>Static text does not act as a <strong>placeholder</strong> with the <strong>correct size</strong>. In the example above from the Weather page of the default Blazor project template, the <em>Loading</em> text has a much lower height compared to the fully rendered table containing the weather information.</p></li><li><p>A code snippet like the <em>Loading</em> text above is not reusable. It doesn&rsquo;t include a CSS class to make it look consistent across pages, nor is it reusable. Copying the same snippet across multiple pages will yield different user experiences if one of the developers decides to alter its design in the future.</p></li></ol><h2 id="a-basic-reusable-loading-indicator-component">A Basic Reusable Loading Indicator Component</h2><p>Let&rsquo;s build a basic <strong>reusable</strong> <code>LoadingIndicator</code> component. First of all, we want to internalize the loading state.</p><p>This helps us get rid of the <code>if-else</code> statement in each page component. We want the code in the page component to look like this:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>LoadingIndicator</span> <span class="token attr-name">IsLoading</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@(forecasts == null)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- code omitted --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>LoadingIndicator</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Let&rsquo;s start with the component template:</p><pre class=" language-csharp"><code class="prism  language-csharp">@<span class="token keyword">if</span> <span class="token punctuation">(</span>IsLoading<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"loading-indicator"</span> Style<span class="token operator">=</span><span class="token string">"@($"</span>height<span class="token punctuation">:</span> <span class="token punctuation">{</span>Height<span class="token punctuation">}</span>px<span class="token string">")"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"circular-progress"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"progress-text"</span><span class="token operator">&gt;</span>Loading<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
<span class="token punctuation">{</span>
    @ChildContent
<span class="token punctuation">}</span>
</code></pre><p>We internalized the <code>if-else</code> statement handling the loading state. During loading, we display a loading indicator, which consists of three <code>div</code>s.</p><p>We show the child content (in the example above, an HTML table) when the loading state is <code>false</code>.</p><p>Now let&rsquo;s look at the code section:</p><pre class=" language-csharp"><code class="prism  language-csharp">@code <span class="token punctuation">{</span>
    <span class="token punctuation">[</span>Parameter<span class="token punctuation">]</span>
    <span class="token keyword">public</span> required <span class="token keyword">int</span> Height <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token number">96</span><span class="token punctuation">;</span>

    <span class="token punctuation">[</span>Parameter<span class="token punctuation">,</span> EditorRequired<span class="token punctuation">]</span>
    <span class="token keyword">public</span> required <span class="token keyword">bool</span> IsLoading <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token punctuation">[</span>Parameter<span class="token punctuation">,</span> EditorRequired<span class="token punctuation">]</span>
    <span class="token keyword">public</span> RenderFragment<span class="token operator">?</span> ChildContent <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Here, we have three component parameters. Let&rsquo;s go through them one by one.</p><p>The <code>Height</code> parameter is optional (notice the absence of the <code>EditorRequired</code> attribute). By default, the height of our loading indicator is <strong>96 pixels</strong>. However, we can provide a custom value to this property for each instance on a page component.</p><p>The <code>IsLoading</code> parameter decides whether the loading indicator or its children are rendered.</p><p>The <code>ChildContent</code> parameter of type <code>RenderFragement</code> allows us to wrap the content of the page into the <code>LoadingIndicator</code> for a good developer experience.</p><p>Now that we have the component template and its behavior, we need the <strong>CSS styling</strong>:</p><pre class=" language-css"><code class="prism  language-css"><span class="token selector"><span class="token class">.loading-indicator</span> </span><span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
    <span class="token property">flex-direction</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
    <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
    <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
    <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">100%</span><span class="token punctuation">;</span>
    <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">8</span>px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.circular-progress</span> </span><span class="token punctuation">{</span>
    <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">32</span>px<span class="token punctuation">;</span>
    <span class="token property">height</span><span class="token punctuation">:</span> <span class="token number">32</span>px<span class="token punctuation">;</span>
    <span class="token property">border</span><span class="token punctuation">:</span> <span class="token number">3</span>px solid <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token number">0</span>, <span class="token number">0</span>, <span class="token number">0</span>, <span class="token number">0.1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">border-top</span><span class="token punctuation">:</span> <span class="token number">3</span>px solid <span class="token hexcode">#3b82f6</span><span class="token punctuation">;</span>
    <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">50%</span><span class="token punctuation">;</span>
    <span class="token property">animation</span><span class="token punctuation">:</span> spin <span class="token number">0.8</span>s linear infinite<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.progress-text</span> </span><span class="token punctuation">{</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">1</span>rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Spinner animation */</span>
<span class="token atrule"><span class="token rule">@keyframes</span> spin</span> <span class="token punctuation">{</span>
    <span class="token selector">0% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">rotate</span><span class="token punctuation">(</span><span class="token number">0</span>deg<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">100% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">rotate</span><span class="token punctuation">(</span><span class="token number">360</span>deg<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>CSS, unfortunately, most of the time requires <strong>a lot of code</strong> to implement rather simple things.</p><p>For example, here, we have the <code>loading-indicator</code> class, which contains a <code>flex</code> layout and its layout properties. It basically takes up the entire available width and places its children one below the other.</p><p>Next, we have the <code>circular-progress</code> class, which defines the circle&rsquo;s layout. It&rsquo;s the base of our animation.</p><p>The <code>progress-text</code> class is simple for now and only sets the <code>font-size</code>.</p><p>Last but not least, we have an <strong>animation</strong> definition using <code>keyframes</code>. We use the named animation in the <code>circular-progress</code> class&rsquo;s animation property.</p><p>Let&rsquo;s see how it works in action.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/loading-indicator.png?sfvrsn=f76d683b_2" title="Loading Indicator Component in a Blazor App" alt="The default Blazor web app project template with a custom loading indicator on the Weather page." /></p><p>I set the delay in the <code>Weather</code> page component to <strong>2 seconds</strong> so that I can see the full loading animation for testing.</p><pre class=" language-csharp"><code class="prism  language-csharp"><span class="token comment">// Simulate asynchronous loading to demonstrate a loading indicator</span>
<span class="token keyword">await</span> Task<span class="token punctuation">.</span><span class="token function">Delay</span><span class="token punctuation">(</span><span class="token number">2000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>As soon as the data is loaded from the screen, the <code>IsLoading</code> property of the <code>LoadingIndicator</code> component will return <code>false</code>. Therefore, instead of the circular progress animation, we will see the pages&rsquo; content.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/rendered-page-content.png?sfvrsn=b7f42a10_2" title="Weather page with weather information" alt="The default Blazor web app project template with the Weather page and rendered weather information." /></p><p><strong>Hint:</strong> One of the advantages of component-oriented web frameworks such as Blazor is that we can reuse this <code>LoadingIndicator</code> component and therefore hide the large CSS definition and the component behavior behind this <code>LoadingIndicator</code> component.</p><h2 id="professional-integrated-solutions">Professional Integrated Solutions</h2><p>While we definitely provided a more useful component and a better user experience with our reusable <code>LoadingIndicator</code> component, there is still room for improvement.</p><p>As application developers, we want to <strong>provide the best solutions for business problems</strong> while providing the <strong>best possible user experience</strong>.</p><p>We should focus on <strong>delivering value</strong> to our business rather than wasting time implementing generic components. Standing on the shoulders of giants is the right call.</p><p>There are professional user interface libraries, such as <a href="https://www.telerik.com/blazor-ui" target="_blank">Progress Telerik UI for Blazor</a>. Developers of those libraries invest much more time into building those reusable components than we are able to spend in our projects.</p><p>Component libraries like Telerik UI for Blazor integrate sophisticated <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/common-features/loading-sign">loading indicators and loading state handling</a> into higher-level components, such as AutoComplete fields, Grid layouts and ListViews, and more advanced components like TreeList and TreeView.</p><h2 id="conclusion">Conclusion</h2><p>Handling the <strong>loading state</strong> and providing a <strong>good user experience</strong> during <strong>asynchronous data fetching operations</strong> is crucial in modern web development.</p><p>The default Blazor web application project template provides a simple solution that lacks in multiple regards.</p><p>We implement a custom <code>LoadingIndicator</code> component, which improves the solution from the default project template by extracting logic and behavior into a <strong>reusable component</strong>. Using its <code>Height</code> property, we can make the loading indicator take the same space as the rendered elements, thus preventing layout shifts. It&rsquo;s a step in the right direction.</p><p>However, if possible, I usually prefer using one of the brilliant, existing solutions over my handmade approach. For example, the <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/common-features/loading-sign">Loader and LoaderContainer components</a> provide a great developer and user experience for building modern Blazor web applications.</p><hr /><blockquote><p>Telerik UI for Blazor comes with a free 30-day trial, so you can explore these plus 120 other components for yourself.</p><br /><p><a target="_blank" href="https://www.telerik.com/try/ui-for-blazor" class="Btn">Try Now</a></p></blockquote><img src="https://feeds.telerik.com/link/10827/17367500.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:f5a4c7a4-71fb-4e97-ab13-8a36d26866be</id>
    <title type="text">Handling Mutations with TanStack Query for Vue</title>
    <summary type="text">Learn how to handle mutations with TanStack Query in Vue to be able to send data back the server and keep the whole app in sync.</summary>
    <published>2026-06-23T19:43:24Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Marina Mosti </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17366165/handling-mutations-tanstack-query-vue"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to handle mutations with TanStack Query in Vue to be able to send data back the server and keep the whole app in sync.</span></p><p>In my previous article on <a target="_blank" href="https://www.telerik.com/blogs/data-fetching-tanstack-query-vue">Data Fetching with TanStack Query for Vue</a>, we went through all the things TanStack Query gives us for free when it comes to pulling data from an API: caching, automatic refetching on window focus, stale times, polling and a much cleaner template than the usual <code>ref</code> plus <code>onMounted</code> dance.</p><p>But of course, fetching data is only half of the story. At some point you&rsquo;re going to need to actually <em>send</em> data back to the server. Creating users, updating records, deleting items, triggering actions. That&rsquo;s where mutations come in!</p><p>In this article we&rsquo;ll take a look at how to handle mutations with TanStack Query in Vue, how to hook into their lifecycle, how to keep the rest of your app in sync after something changes, and a little bit on optimistic updates.</p><h2 id="what-is-a-mutation">What Is a Mutation?</h2><p>In the context of TanStack Query, a mutation is any operation that changes server state. <code>POST</code>, <code>PUT</code>, <code>PATCH</code>, <code>DELETE</code>, basically anything that isn&rsquo;t a <code>GET</code>. Queries fetch data; mutations change it.</p><p>The reason TanStack Query treats mutations as their own concept instead of just &ldquo;another query&rdquo; is because they behave very differently:</p><ul><li>Queries run automatically when a component mounts or when their key changes.</li><li>Mutations are fired manually, usually as a reaction to a user action like submitting a form or clicking a button.</li><li>Queries are cached. Mutations are not.</li><li>After a mutation succeeds, other queries might now hold outdated data that we need to refresh.</li></ul><p>We&rsquo;ll address all of these, let&rsquo;s start with the basics.</p><h2 id="your-first-mutation-with-usemutation">Your First Mutation with useMutation</h2><p>The composable we&rsquo;re going to use is <code>useMutation</code>, and the API is refreshingly simple. Let&rsquo;s build a form that creates a new user.</p><p><code>CreateUser.vue</code></p><pre class=" language-vue"><code class="prism  language-vue">&lt;script setup&gt;
import { ref } from 'vue'
import { useMutation } from '@tanstack/vue-query'

const name = ref('')
const email = ref('')

const createUser = async (payload) =&gt; {
  const response = await fetch('https://myapp.com/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  })

  if (!response.ok) {
    throw new Error('Failed to create user')
  }

  return response.json()
}

const { mutate, isPending, isError, error } = useMutation({
  mutationFn: createUser,
})

const onSubmit = () =&gt; {
  mutate({ name: name.value, email: email.value })
}
&lt;/script&gt;

&lt;template&gt;
  &lt;form @submit.prevent="onSubmit"&gt;
    &lt;input v-model="name" placeholder="Name" /&gt;
    &lt;input v-model="email" placeholder="Email" /&gt;
    &lt;button :disabled="isPending" type="submit"&gt;
      {{ isPending ? 'Saving...' : 'Create user' }}
    &lt;/button&gt;
    &lt;p v-if="isError"&gt;Something went wrong: {{ error.message }}&lt;/p&gt;
  &lt;/form&gt;
&lt;/template&gt;
</code></pre><p>Let&rsquo;s break it down. <code>useMutation</code> takes a configuration object with one essential property:</p><ul><li><strong><code>mutationFn</code></strong>: The async function that actually performs the mutation. It <strong>must</strong> return a promise. If the promise rejects, TanStack Query considers the mutation failed.</li></ul><p>Notice that unlike <code>useQuery</code>, there&rsquo;s no <code>mutationKey</code> required here. Mutations can be given a key for advanced scenarios, but for most applications you&rsquo;ll never need one.</p><p>The composable returns several reactive properties, and the ones you&rsquo;ll end up using the most are:</p><ul><li><strong><code>mutate</code></strong>: The function you call to actually trigger the mutation. Any arguments you pass here are forwarded as the first parameter of your <code>mutationFn</code>.</li><li><strong><code>isPending</code></strong>: A boolean that is <code>true</code> while the mutation is in flight. This one used to be called <code>isLoading</code> in older versions, so if you come across old examples online, that&rsquo;s why.</li><li><strong><code>isError</code> / <code>isSuccess</code></strong>: Booleans that reflect the final state of the last attempt.</li><li><strong><code>error</code></strong>: Whatever error was thrown from the <code>mutationFn</code> if it failed.</li><li><strong><code>data</code></strong>: The resolved value from the <code>mutationFn</code> if it succeeded.</li></ul><p>I can&rsquo;t stress enough how much cleaner this ends up being compared to writing your own <code>try/catch</code> plus a <code>loading</code> ref plus an <code>error</code> ref every single time you need a form submission.</p><h2 id="mutate-vs-mutateasync">mutate vs. mutateAsync</h2><p><code>useMutation</code> actually returns two different functions that you can use to trigger the mutation: <code>mutate</code> and <code>mutateAsync</code>. They do the same thing but in different ways.</p><ul><li><code>mutate(variables)</code> is fire and forget. It does not return a promise. Errors are swallowed by TanStack Query and surfaced through the reactive <code>isError</code> and <code>error</code> properties. You cannot <code>await</code> it.</li><li><code>mutateAsync(variables)</code> returns a promise that you can <code>await</code>. If the mutation fails, the promise rejects, and you&rsquo;re expected to handle the error yourself with a try/catch.</li></ul><p>I normally use <code>mutate</code> most of the time because the reactive state is usually all I need. <code>mutateAsync</code> is really nice when you need to chain multiple operations together or when you&rsquo;re inside a larger async flow and you want the mutation to behave like any other awaited call.</p><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{</span> mutateAsync <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useMutation</span><span class="token punctuation">(</span><span class="token punctuation">{</span> mutationFn<span class="token punctuation">:</span> createUser <span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> onSubmit <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">mutateAsync</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token punctuation">:</span> name<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">)</span>
    router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`/users/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>user<span class="token punctuation">.</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">err</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Could not create user'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>A word of caution: if you use <code>mutateAsync</code> and forget the try/catch, you&rsquo;ll get an unhandled promise rejection warning in your console.</p><h2 id="lifecycle-callbacks">Lifecycle Callbacks</h2><p>Let&rsquo;s dive into the juicy bits of mutations now.</p><p>One of the things that makes <code>useMutation</code> so useful in real applications is the set of lifecycle callbacks it exposes. You can pass them either when you create the mutation or when you call <code>mutate</code>.</p><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{</span> mutate <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useMutation</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  mutationFn<span class="token punctuation">:</span> createUser<span class="token punctuation">,</span>
  onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span>data<span class="token punctuation">,</span> variables<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// data is what mutationFn returned</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'User created!'</span><span class="token punctuation">,</span> data<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  onError<span class="token punctuation">:</span> <span class="token punctuation">(</span>error<span class="token punctuation">,</span> variables<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Something broke'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  onSettled<span class="token punctuation">:</span> <span class="token punctuation">(</span>data<span class="token punctuation">,</span> error<span class="token punctuation">,</span> variables<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// Runs no matter what, after onSuccess or onError</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><p>The three callbacks you&rsquo;ll use the most are:</p><ul><li><strong><code>onSuccess</code></strong>: Fires when the mutation resolves successfully. Perfect for showing a toast, closing a modal, resetting a form or navigating away.</li><li><strong><code>onError</code></strong>: Fires when the mutation rejects. Great for surfacing error messages to the user.</li><li><strong><code>onSettled</code></strong>: Fires after either <code>onSuccess</code> or <code>onError</code>. Ideal for cleanup logic that needs to run regardless of outcome.</li></ul><p>Keep in mind that you can also pass these callbacks directly to the <code>mutate</code>:</p><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token function">mutate</span><span class="token punctuation">(</span>payload<span class="token punctuation">,</span> <span class="token punctuation">{</span>
  onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">showToast</span><span class="token punctuation">(</span><span class="token string">'Saved!'</span><span class="token punctuation">)</span>
    <span class="token function">closeModal</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><p>If you define callbacks in both places, both will run. The ones on <code>useMutation</code> fire first, then the ones passed to <code>mutate</code>. Remember this if you end up seeing duplicate toasts or double navigations!</p><p>Normally you would use the <code>mutate</code> call callbacks whenever you need a specific call of the mutation to do something additional to what is already defined on the <code>useMutation</code> call.</p><h2 id="invalidating-queries-after-a-mutation">Invalidating Queries After a Mutation</h2><p>Here&rsquo;s where mutations really start to shine, and where most of the real world value of TanStack Query lives.</p><p>Picture this scenario. You have a user list page that uses <code>useQuery</code> with the key <code>['users']</code>. The user clicks a button to create a new user, the mutation fires, the backend responds happily with a 201, and&hellip; <em>queue drumroll</em>, the list on the screen still shows the old data. The cache has no idea anything changed.</p><p>The fix is to tell TanStack Query that the <code>['users']</code> query is now stale and should be refetched. We do that via the query client&rsquo;s <code>invalidateQueries</code> method.</p><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> useMutation<span class="token punctuation">,</span> useQueryClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@tanstack/vue-query'</span>

<span class="token keyword">const</span> queryClient <span class="token operator">=</span> <span class="token function">useQueryClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> <span class="token punctuation">{</span> mutate <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useMutation</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  mutationFn<span class="token punctuation">:</span> createUser<span class="token punctuation">,</span>
  onSuccess<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    queryClient<span class="token punctuation">.</span><span class="token function">invalidateQueries</span><span class="token punctuation">(</span><span class="token punctuation">{</span> queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'users'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><p>Any query with a matching key is marked stale and, if it is being observed by a mounted component, refetched immediately. If no component is currently observing it, it will simply be refetched the next time it gets mounted.</p><p>Pay close attention to what you set to the <code>queryKey</code>!</p><p><code>invalidateQueries({ queryKey: ['users'] })</code> will also invalidate <code>['users', 1]</code>, <code>['users', 2]</code> and so on. This default behavior is usually what you will want for you applications, and you will end up setting up keys with specific words like <code>users</code> that you want to invalidate in groups.</p><p>If you only want to invalidate exact matches, you can pass <code>exact: true</code>.</p><pre class=" language-javascript"><code class="prism  language-javascript">queryClient<span class="token punctuation">.</span><span class="token function">invalidateQueries</span><span class="token punctuation">(</span><span class="token punctuation">{</span> queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'users'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> exact<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><p>I&rsquo;ve found that 95% of the mutations I write end up following the exact same shape: do the thing, then invalidate the related list and/or detail queries. Once this clicks for you, you&rsquo;ll start thinking of your data in terms of which queries each mutation affects.</p><h2 id="optimistic-updates">Optimistic Updates</h2><p>Sometimes waiting for the server feels sluggish. A user clicks &ldquo;like&rdquo; on a post, and the heart icon just sits there for 300ms while the request round trips. The fix for this is optimistic updates: update the UI as if the mutation already succeeded, then reconcile with the server afterward.</p><p>TanStack Query has first class support for this through the <code>onMutate</code> callback. The general idea goes like this:</p><ol><li>On <code>onMutate</code>, cancel any in flight queries for the related key, grab a snapshot of the current cached data, and write the optimistic value into the cache.</li><li>Return the snapshot from <code>onMutate</code> so you can use it later.</li><li>On <code>onError</code>, roll back to the snapshot.</li><li>On <code>onSettled</code>, invalidate the query to make sure the real server data eventually wins.</li></ol><pre class=" language-javascript"><code class="prism  language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">likePost</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> <span class="token function">someApiCall</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
<span class="token keyword">const</span> queryClient <span class="token operator">=</span> <span class="token function">useQueryClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> <span class="token punctuation">{</span> mutate <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useMutation</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  mutationFn<span class="token punctuation">:</span> likePost<span class="token punctuation">,</span>
  onMutate<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>postId<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> queryClient<span class="token punctuation">.</span><span class="token function">cancelQueries</span><span class="token punctuation">(</span><span class="token punctuation">{</span> queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'posts'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

    <span class="token keyword">const</span> previousPosts <span class="token operator">=</span> queryClient<span class="token punctuation">.</span><span class="token function">getQueryData</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'posts'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>

    <span class="token comment">// We find the postId and add +1 the likes in the query data</span>
    queryClient<span class="token punctuation">.</span><span class="token function">setQueryData</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'posts'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>old<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
      old<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> p<span class="token punctuation">.</span>id <span class="token operator">===</span> postId <span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token operator">...</span>p<span class="token punctuation">,</span> likes<span class="token punctuation">:</span> p<span class="token punctuation">.</span>likes <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span> <span class="token punctuation">:</span> p<span class="token punctuation">)</span>
    <span class="token punctuation">)</span>

    <span class="token comment">// Don't forget to retun the modified data!</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span> previousPosts <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  onError<span class="token punctuation">:</span> <span class="token punctuation">(</span>err<span class="token punctuation">,</span> variables<span class="token punctuation">,</span> context<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// The `context` here is what we returned in onMutate</span>
    queryClient<span class="token punctuation">.</span><span class="token function">setQueryData</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'posts'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> context<span class="token punctuation">.</span>previousPosts<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  onSettled<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    queryClient<span class="token punctuation">.</span><span class="token function">invalidateQueries</span><span class="token punctuation">(</span><span class="token punctuation">{</span> queryKey<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'posts'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><p>To be quite honest with you, optimistic updates are one of those features that sound wonderful on paper but that I only reach for when the UX genuinely demands it.</p><p>For the vast majority of forms and buttons in a typical CRUD app, the plain old &ldquo;show a spinner, invalidate on success&rdquo; flow is perfectly fine and a lot easier to reason about. Reach for optimistic updates when the snappiness actually matters, not by default.</p><h2 id="wrapping-up">Wrapping Up</h2><p>Mutations are the missing half of the TanStack Query story, and once you pair them with <code>invalidateQueries</code>, the library really starts to pay for itself. You get a consistent way to handle every form, every button, every &ldquo;do something on the server&rdquo; action across your entire app. No more scattered loading refs, no more forgetting to refetch data after an update.</p><p>Today we covered the basics of <code>useMutation</code>, the difference between <code>mutate</code> and <code>mutateAsync</code>, the lifecycle callbacks, query invalidation and a quick look at optimistic updates. From here I&rsquo;d recommend poking around the <a target="_blank" href="https://tanstack.com/query/latest/docs/framework/vue/guides/mutations">official mutations guide</a> to see the more advanced patterns like mutation scopes and retry configuration.</p><p>Happy mutating!</p><img src="https://feeds.telerik.com/link/10827/17366165.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:2698e963-de43-4919-a0fe-cc92e5a6cf21</id>
    <title type="text">Getting Started with NLP Using Hugging Face Transformers in Python</title>
    <summary type="text">Learn about natural language processing and explore the Hugging Face Transformers library in Python for tasks like text classification and summarization.</summary>
    <published>2026-06-23T17:10:00Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17366166/getting-started-nlp-using-hugging-face-transformers-python"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn about natural language processing and explore the Hugging Face Transformers library in Python for tasks like text classification and summarization.</span></p><p>Natural Language Processing (NLP) focuses on enabling computers to understand, analyze and generate human language.</p><p>Modern NLP systems are largely powered by <strong>transformer architectures</strong>, which introduced the self-attention mechanism to model relationships between words regardless of their position in a sentence. This approach significantly improved performance on tasks such as text classification, summarization, translation and question answering, while also enabling models to capture long-range context more efficiently than earlier methods, such as recurrent neural networks (RNNs).</p><p>Popular transformer models include:</p><ul><li>BERT (Bidirectional Encoder Representations from Transformers)</li><li>GPT (Generative Pre-trained Transformer)</li><li>RoBERTa</li><li>DistilBERT</li><li>T5</li></ul><p>These models are pretrained on massive text datasets and can be fine-tuned for specific NLP tasks.</p><p><strong><a target="_blank" href="https://huggingface.co/">Hugging Face</a></strong> has become one of the most popular platforms for working with these models, providing easy-to-use tools, pretrained transformer models and Python libraries that allow developers to build powerful NLP applications with minimal code.</p><p>In this article, we will explore the basics of NLP using the <a target="_blank" href="https://huggingface.co/docs/transformers/en/index">Hugging Face Transformers</a> library in Python, demonstrating how to implement common tasks such as text classification and text summarization using modern transformer models.</p><p>The Hugging Face Transformers library includes thousands of pretrained models that can be easily downloaded and used with just a few lines of Python code.</p><p>Key components of the Hugging Face ecosystem include:</p><ul><li>Transformers library for pretrained models</li><li>A dataset library for loading NLP datasets</li><li>Tokenizers for efficient text processing</li><li>Hugging Face Hub for sharing models and datasets</li></ul><p>The library supports both <strong>PyTorch and TensorFlow</strong>, making it flexible for different deep learning workflows.</p><h2 id="setting-up-the-environment">Setting Up the Environment</h2><p>In this tutorial, I assume you are new to Python. First, verify that Python is installed on your system. Then run the following commands to check the Python version and create or activate a virtual environment before installing the required dependencies.</p><ul><li><code>python3 --version</code></li><li><code>python3 -m venv .venv</code></li><li><code>source .venv/bin/activate</code></li></ul><p>After that, run the command to install transformers in the project.</p><ul><li><code>pip3 install transformers torch</code></li></ul><p>After that, add requirement.txt file in your project, and add entry:</p><pre><code>pandas&gt;=2.0.0
</code></pre><p>And then again run the command <code>pip3 install -r requirements.txt</code>.</p><p>At this point, you have installed all the required dependencies and set up the Python project environment. Now we can start building some NLP pipelines using the libraries we configured.</p><h2 id="text-classification">Text Classification</h2><p>Text classification is one of the most common NLP tasks. It involves assigning predefined categories to text. Examples include sentiment analysis, spam detection and topic classification.</p><p>Using Hugging Face, we can create a text classification model in just a few lines of Python, as shown below.</p><pre class=" language-python"><code class="prism  language-python"><span class="token keyword">from</span> transformers <span class="token keyword">import</span> pipeline
<span class="token keyword">import</span> pandas <span class="token keyword">as</span> pd 

classifier <span class="token operator">=</span> pipeline<span class="token punctuation">(</span><span class="token string">"text-classification"</span><span class="token punctuation">)</span>

output <span class="token operator">=</span> classifier<span class="token punctuation">(</span><span class="token string">"I am excited for final cricket match"</span><span class="token punctuation">)</span>
df <span class="token operator">=</span> pd<span class="token punctuation">.</span>DataFrame<span class="token punctuation">(</span>output<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span>df<span class="token punctuation">)</span>
</code></pre><p>You should get the output shown below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/hugging-face-label-score-1.png?sfvrsn=ec357b83_2" alt="Label – positive. Score .99969" /></p><p>In this example, the pipeline automatically loads a pretrained transformer model that performs sentiment analysis. The model analyzes the text and predicts whether the sentiment is positive or negative.</p><h2 id="pipeline">Pipeline</h2><p>The pipeline is a helper function, that performs three tasks.</p><ol><li>Preprocess &ndash; turn raw input into what model needs</li><li>Run the model &ndash; run the model with given input</li><li>Postprocess &ndash; turn model output into label, score or translated text</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/preprocess-runningmodel-postprocess.png?sfvrsn=e82874d2_2" alt="Preprocess – Running model – Postprocess" /></p><p>Essentially it takes a raw input and gives you clean output.</p><h2 id="named-entity-recognition">Named Entity Recognition</h2><p>Using the pipeline wrapper, it is very easy to work with Named Entity Recognition (NER).</p><pre class=" language-python"><code class="prism  language-python"><span class="token keyword">from</span> transformers <span class="token keyword">import</span> pipeline
<span class="token keyword">import</span> pandas <span class="token keyword">as</span> pd
tags <span class="token operator">=</span> pipeline<span class="token punctuation">(</span><span class="token string">"ner"</span><span class="token punctuation">,</span>aggregation_strategy<span class="token operator">=</span><span class="token string">"simple"</span><span class="token punctuation">)</span>

customer_feedback <span class="token operator">=</span> <span class="token string">"Barack Obama visited Tokyo in April 2014 and met with Shinzo Abe. The two leaders discussed trade agreements between the United States and Japan. Later, Obama gave a speech at the Roppongi Hills complex. The New York Times covered the event."</span>
output <span class="token operator">=</span> tags<span class="token punctuation">(</span>customer_feedback<span class="token punctuation">)</span>
df <span class="token operator">=</span> pd<span class="token punctuation">.</span>DataFrame<span class="token punctuation">(</span>output<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span>df<span class="token punctuation">)</span>
</code></pre><p>We are using Hugging Face NER pipeline to process feedback text, automatically identify named entities (such as people, locations and organizations). After converting the extracted entities into a tabular format using the <code>pandas data frame=</code>, you should get this output:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/hugging-face-tabular-ner.png?sfvrsn=bf487ca6_2" alt="Table with entity group, score, word, start, end" /></p><p>In the example above, we use the NER pipeline to identify named entities in text, such as people, places and organizations.</p><p>The <code>aggregation_strategy="simple"</code> option is used to merge subword tokens back into complete entities. Without this setting, some models may split words into subword pieces (for example, &ldquo;Obama&rdquo; may appear as &ldquo;Ob&rdquo; and &ldquo;##ama&rdquo;). Using the &ldquo;simple&rdquo; aggregation strategy keeps these fragments combined and returned as a single entity span (such as &ldquo;Obama&rdquo;).</p><h2 id="text-summarization">Text Summarization</h2><p>Let&rsquo;s try text summarization without using pipeline. We can do that in three steps as shown below:</p><pre class=" language-python"><code class="prism  language-python"><span class="token keyword">from</span> transformers <span class="token keyword">import</span> AutoTokenizer<span class="token punctuation">,</span> AutoModelForSeq2SeqLM

model_name <span class="token operator">=</span> <span class="token string">"facebook/bart-large-cnn"</span>
tokenizer <span class="token operator">=</span> AutoTokenizer<span class="token punctuation">.</span>from_pretrained<span class="token punctuation">(</span>model_name<span class="token punctuation">)</span>
model <span class="token operator">=</span> AutoModelForSeq2SeqLM<span class="token punctuation">.</span>from_pretrained<span class="token punctuation">(</span>model_name<span class="token punctuation">)</span>
text <span class="token operator">=</span> <span class="token triple-quoted-string string">"""
 your text 
"""</span>

inputs <span class="token operator">=</span> tokenizer<span class="token punctuation">(</span>
    text<span class="token punctuation">,</span>
    return_tensors<span class="token operator">=</span><span class="token string">"pt"</span><span class="token punctuation">,</span>
    max_length<span class="token operator">=</span><span class="token number">1024</span><span class="token punctuation">,</span>
    truncation<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
    padding<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>

outputs <span class="token operator">=</span> model<span class="token punctuation">.</span>generate<span class="token punctuation">(</span>
    <span class="token operator">**</span>inputs<span class="token punctuation">,</span>
    max_length<span class="token operator">=</span><span class="token number">150</span><span class="token punctuation">,</span>
    min_length<span class="token operator">=</span><span class="token number">30</span><span class="token punctuation">,</span>
    num_beams<span class="token operator">=</span><span class="token number">4</span><span class="token punctuation">,</span>
    early_stopping<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>

summary <span class="token operator">=</span> tokenizer<span class="token punctuation">.</span>decode<span class="token punctuation">(</span>outputs<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> skip_special_tokens<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span>summary<span class="token punctuation">)</span>
</code></pre><p>The example above follows these steps:</p><ol><li>Loading the model</li><li>Loading the tokenizer</li><li>Tokenizing the input</li><li>Generating the summary</li><li>Decoding the output and printing</li></ol><p>We are following all steps of preprocessing, running the model and the postprocessing as we are not using pipeline. This should give you an idea about pipeline utility function.</p><p>So, transformers are particularly powerful for NLP because they process text in parallel and capture context efficiently. The self-attention mechanism allows the model to determine which words in a sentence are most relevant when interpreting meaning.</p><p>For example, in the sentence:<br /><strong>&ldquo;Apple released a new product.&rdquo;</strong><br />The word <strong>Apple</strong> could refer to a fruit or a technology company. A transformer model can use surrounding words like <em>released</em> and <em>product</em> to infer that the sentence refers to the company.</p><p>This contextual understanding is one of the major breakthroughs that transformer models introduced.</p><p>Transformer-based NLP systems are now used in many real-world applications:</p><ul><li>Chatbots and virtual assistants</li><li>Automatic document summarization</li><li>Email spam filtering</li><li>Customer sentiment analysis</li><li>Search engines</li><li>Language translation</li><li>Code generation tools</li></ul><p>Companies increasingly rely on transformer models to analyze large volumes of text data and automate tasks that previously required human interpretation.</p><p>I hope that you now have a solid understanding of transformers. Thanks for reading this article.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Build an LLM Chat App Using LangGraph, OpenAI and Python</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Learn how to get started in AI development with <a target="_blank" href="https://www.telerik.com/blogs/build-llm-chat-app-using-langgraph--openai-python-part-1">LangChain and OpenAI by making a Python</a> chat app.</p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17366166.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:7d2311da-a6e9-4adc-9115-599ebd10665b</id>
    <title type="text">Nuxt 4 Server Routes vs. Fetch Composables</title>
    <summary type="text">See a Nuxt app load data from the server in a Server Component and using useFetch to see how Server Components and fetch mechanisms compare.</summary>
    <published>2026-06-18T17:23:23Z</published>
    <updated>2026-07-14T00:42:49Z</updated>
    <author>
      <name>Jonathan Gamble </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/10827/17363387/nuxt-4-server-routes-vs-fetch-composables"/>
    <content type="text"><![CDATA[<p><span class="featured">See a Nuxt app load data from the server in a Server Component and using useFetch to see how Server Components and fetch mechanisms compare.</span></p><p>There are currently two ways to load data from the server and hydrate it. Nuxt has Server Components, just like React, as well as fetch mechanisms API route hydration.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image.png?sfvrsn=74a12829_2" alt="Hello World, server time, test schema, home, server component, fetch" /></p><h2 id="tldr">TL;DR</h2><p>This app will load data from the server in a Server Component and using <code>useFetch</code>. Both mechanisms work similarly from the server perspective, but one method hydrates data from the server and sets it as reactive, while the other caches data from the server. Both components can be validated with <a href="http://schema.org">schema.org</a> to verify the data is properly loaded.</p><h2 id="nuxt-setup">Nuxt Setup</h2><p>We must properly config the layout and components.</p><h3 id="configure-tailwind">Configure Tailwind</h3><p>Follow the <a href="https://tailwindcss.com/docs/installation/framework-guides/nuxt">Nuxt 4 Tailwind Guide</a> for the latest instructions.</p><h3 id="nuxt-config">Nuxt Config</h3><p>Make sure to enable component islands with deep selective client. This enables server components and client components inside of them. For more on Nuxt Server Components, see my other article <a href="https://www.telerik.com/blogs/nuxt-3-server-components-rock">Nuxt 3 Server Components Rock</a>.</p><pre class=" language-tsx"><code class="prism  language-tsx">import tailwindcss from "@tailwindcss/vite";

export default defineNuxtConfig({
  compatibilityDate: "2025-07-15",
  devtools: { enabled: true },
  css: ['./app/assets/css/main.css'],
  experimental: {
    componentIslands: {
      selectiveClient: 'deep',
    },
  },
  vite: {
    plugins: [
      tailwindcss(),
    ],
  },
});
</code></pre><h3 id="configure-appapp.vue-for-pages-and-layouts">Configure app/app.vue for Pages and Layouts</h3><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NuxtLayout</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NuxtPage</span> <span class="token punctuation">/&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>NuxtLayout</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
</code></pre><h3 id="configure-the-layout-at-applayoutsdefault.vue">Configure the Layout at app/layouts/default.vue</h3><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex flex-col items-center gap-4 p-10<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>slot</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>flex gap-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NuxtLink</span> <span class="token attr-name">to</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/<span class="token punctuation">"</span></span> <span class="token attr-name">active-class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>font-bold<span class="token punctuation">"</span></span> <span class="token attr-name">exact-active-class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>font-bold<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        Home
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>NuxtLink</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NuxtLink</span>
        <span class="token attr-name">to</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/server<span class="token punctuation">"</span></span>
        <span class="token attr-name">active-class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>font-bold<span class="token punctuation">"</span></span>
        <span class="token attr-name">exact-active-class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>font-bold<span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span>
        Server Component
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>NuxtLink</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>NuxtLink</span>
        <span class="token attr-name">to</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/fetch<span class="token punctuation">"</span></span>
        <span class="token attr-name">active-class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>font-bold<span class="token punctuation">"</span></span>
        <span class="token attr-name">exact-active-class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>font-bold<span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span>
        Fetch
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>NuxtLink</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>This allows bolded current routes.</p><h3 id="homepage-at-apppagesindex.vue">Homepage at app/pages/index.vue</h3><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>border p-4 rounded-xl<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    Welcome to the Server Components VS Fetch demo!
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
</code></pre><h3 id="validate-component-at-appcomponentsvalidate.vue">Validate Component at app/components/validate.vue</h3><p>This is used to create a dynamic link to <a href="http://schema.org">schema.org</a>.</p><pre class=" language-html"><code class="prism  language-html"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ts<span class="token punctuation">"</span></span> <span class="token attr-name">setup</span><span class="token punctuation">&gt;</span></span><span class="token script language-javascript">
<span class="token keyword">const</span> currentUrl <span class="token operator">=</span> <span class="token function">useRequestURL</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> href <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span>
  <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
    <span class="token template-string"><span class="token string">`https://validator.schema.org/#url=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>currentUrl<span class="token punctuation">.</span>href<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>underline hover:no-underline<span class="token punctuation">"</span></span> <span class="token attr-name">:href</span><span class="token punctuation">&gt;</span></span>Test Schema<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
</code></pre><blockquote><p>Notice <code>useRequestURL()</code> can get the current URL safely.</p></blockquote><h2 id="meta-data-and-schema">Meta Data and Schema</h2><p>Nuxt has a built-in composable, <code>useHead</code>, that allows you to set data directly in the header on the server.</p><pre class=" language-tsx"><code class="prism  language-tsx">useHead({
  meta: [
    {
      property: "article:modified_time",
      content: modifiedTime.data.value,
    },
    {
      name: "last-modified",
      content: modifiedTime.data.value,
    },
  ],
  script: [
    {
      type: "application/ld+json",
      textContent: () =&gt;
        JSON.stringify({
          "@context": "https://schema.org",
          "@type": "WebPage",
          dateModified: modifiedTime.data.value,
        }),
    },
  ],
});
</code></pre><p>You can create a <code>meta</code> tag with the <code>meta</code> property, and set the data that you see fit. This is imperative for SEO. Modern search engines group data using JSON-LD and <a href="http://schema.org">schema.org</a>, which requires a formatted <code>script</code> tag.</p><p>The following examples will set the modified date as the fetch date. This is technically incorrect, as you would want this static, but you can see the usefulness of this for dynamically generated pages with good SEO techniques.</p><h2 id="fetch-with-useasyncdata">Fetch with useAsyncData</h2><p>You can fetch data with <code>useFetch</code> if you have an endpoint, or <code>useAsyncData</code> if you just want to run a safe function directly on the server.</p><h3 id="basic-fetch-page-at-apppagesfetch.vue">Basic Fetch Page at app/pages/fetch.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;template&gt;Hello World! &lt;Server-Time-Client /&gt;&lt;/template&gt;
</code></pre><blockquote><p>I love not having to manually import components in the <code>components</code> directory!</p></blockquote><h3 id="here-we-create-appcomponentsserver-time-client.vue">Here We Create app/components/server-time-client.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script setup lang="ts"&gt;
const modifiedTime = await useAsyncData("time", async () =&gt; {
  return new Date().toISOString();
});

useHead({
  meta: [
    {
      property: "article:modified_time",
      content: modifiedTime.data.value,
    },
    {
      name: "last-modified",
      content: modifiedTime.data.value,
    },
  ],
  script: [
    {
      type: "application/ld+json",
      textContent: () =&gt;
        JSON.stringify({
          "@context": "https://schema.org",
          "@type": "WebPage",
          dateModified: modifiedTime.data.value,
        }),
    },
  ],
});
&lt;/script&gt;

&lt;template&gt;
  &lt;div v-if="modifiedTime.data"&gt;Server time: {{ modifiedTime.data.value }}&lt;/div&gt;
  &lt;Validate /&gt;
&lt;/template&gt;
</code></pre><ul><li>We don&rsquo;t have to have <code>client</code> in the name, but it is good to differentiate in this example.</li><li>With <code>useAsyncData</code>, we load data on the server and hydrate it to the browser keeping it reactive. We could have equally created an endpoint at <code>server/api/time.ts</code> and called it with <code>useFetch</code>.</li><li>Your real data will probably be async and will pull from a database.</li></ul><h2 id="server-component">Server Component</h2><p>We can also load the data directly in the HTML on the server, similar to PHP. It will NOT be reactive.</p><h3 id="basic-server-page-at-apppagesserver.vue">Basic Server Page at app/pages/server.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;template&gt;Hello World! &lt;Server-Time&gt;&lt;Validate /&gt;&lt;/Server-Time&gt;&lt;/template&gt;
</code></pre><p>We are loading a client component, <code>validate</code>, inside a server component. This is reactive and depends on the current URL. It must use a <code>&lt;slot /&gt;</code> to work correctly. This is why we enabled <code>deep</code> in <code>nuxt.config.ts</code>. Again, see <a href="https://www.telerik.com/blogs/nuxt-3-server-components-rock">Nuxt 3 Server Components Rock</a>.</p><h3 id="server-time-component-at-appcomponentsserver-time.server.vue">Server Time Component at app/components/server-time.server.vue</h3><pre class=" language-tsx"><code class="prism  language-tsx">&lt;script setup lang="ts"&gt;
const modifiedTime = new Date().toISOString();

useHead({
  meta: [
    {
      property: "article:modified_time",
      content: modifiedTime,
    },
    {
      name: "last-modified",
      content: modifiedTime,
    },
  ],
  script: [
    {
      type: "application/ld+json",
      textContent: () =&gt;
        JSON.stringify({
          "@context": "https://schema.org",
          "@type": "WebPage",
          dateModified: modifiedTime,
        }),
    },
  ],
});
&lt;/script&gt;

&lt;template&gt;
  &lt;div class="flex flex-col gap-4 items-center"&gt;
    &lt;div&gt;Server time: {{ modifiedTime }}&lt;/div&gt;
    &lt;slot /&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><ul><li>A Server Component <em>must</em> have the <code>.server.ts</code> extension to load correctly.</li><li>We can just put our server code directly in the header. None of the JavaScript gets loaded in the browser for this component.</li></ul><h2 id="comparison">Comparison</h2><p>So what is the difference?</p><table><style>table, th, td {
  border: 1px;
  border-color: #bdbdba;
  border-style: dotted;
  border-collapse: collapse;
  margin-right: auto;
  cellspacing="5";
  text-align :left;
}
</style>
 <thead><tr><th style="width:33.3333%;padding:5px;">Aspect</th><th style="width:33.3333%;padding:5px;">Server components</th><th style="width:33.3333%;padding:5px;"><code>useFetch</code> / <code>useAsyncData</code></th></tr></thead><tbody><tr><td style="width:33.3333%;padding:5px;">Main purpose</td><td style="width:33.3333%;padding:5px;">Render UI on server</td><td style="width:33.3333%;padding:5px;">Load reactive data</td></tr><tr><td style="width:33.3333%;padding:5px;">Output</td><td style="width:33.3333%;padding:5px;">HTML</td><td style="width:33.3333%;padding:5px;">Data refs</td></tr><tr><td style="width:33.3333%;padding:5px;">Client JS</td><td style="width:33.3333%;padding:5px;">Less / none for island</td><td style="width:33.3333%;padding:5px;">Normal hydrated component</td></tr><tr><td style="width:33.3333%;padding:5px;">Best for</td><td style="width:33.3333%;padding:5px;">Static or mostly static UI</td><td style="width:33.3333%;padding:5px;">Interactive data-driven UI</td></tr><tr><td style="width:33.3333%;padding:5px;">Data state</td><td style="width:33.3333%;padding:5px;">Props in, HTML out</td><td style="width:33.3333%;padding:5px;"><code>data</code>, <code>pending</code>, <code>error</code></td></tr><tr><td style="width:33.3333%;padding:5px;">Refresh behavior</td><td style="width:33.3333%;padding:5px;">Re-render island</td><td style="width:33.3333%;padding:5px;"><code>refresh()</code> / reactive reload</td></tr><tr><td style="width:33.3333%;padding:5px;">Good example</td><td style="width:33.3333%;padding:5px;">Server-rendered timestamp block</td><td style="width:33.3333%;padding:5px;">Posts, user, notes, lists</td></tr></tbody></table><br /><p>Generally speaking, Fetch Composables can be reactive and load JavaScript. Server Components just load the data as if it were static HTML. This is clear when you navigate between pages, the Server Component does not reload the date, while the Fetch Component does.</p><h3 id="testing-schema">Testing Schema</h3><p>You can click the <code>test schema</code> button to verify the data is loaded from the server and not client, and that it loads correctly.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-06/image-1.png?sfvrsn=22412d3d_2" alt="webpage 0 errors" /></p><p>If you&rsquo;re loading something quickly, use Server Components. If you need dynamic data, use Fetch Composables.</p><p>That&rsquo;s a wrap!</p><p><strong>Repo:</strong> <a href="https://github.com/jdgamble555/nuxt-server-vs-middleware">GitHub</a><br /><strong>Demo:</strong> <a href="https://nuxt-server-vs-middleware.vercel.app/">Vercel</a>
</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Pure Surreal Database Authentication in Nuxt</h4></div><div class="col-8"><p class="u-fs16 u-mb0">See how <a target="_blank" href="https://www.telerik.com/blogs/pure-surreal-database-authentication-nuxt">Nuxt pairs up with Surreal Database</a> with a sample app enabling login, register, logout and password change options with route guards and server-safe APIs.</p></div></div></aside><img src="https://feeds.telerik.com/link/10827/17363387.gif" height="1" width="1"/>]]></content>
  </entry>
</feed>
