<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Muhabbat Ali</title>
    <description>The latest articles on Forem by Muhabbat Ali (@muhabbat_dev).</description>
    <link>https://forem.com/muhabbat_dev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F467622%2F7e33bf8f-a04a-4ac9-9730-0babe302da64.png</url>
      <title>Forem: Muhabbat Ali</title>
      <link>https://forem.com/muhabbat_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/muhabbat_dev"/>
    <language>en</language>
    <item>
      <title>Ansible and GitOps: A Practical Guide</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Tue, 30 Sep 2025 10:41:17 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/ansible-and-gitops-a-practical-guide-1m3n</link>
      <guid>https://forem.com/muhabbat_dev/ansible-and-gitops-a-practical-guide-1m3n</guid>
      <description>&lt;p&gt;If you're in the DevOps space, you’ve probably used Ansible. You also can't miss the buzz around GitOps. This often leads to a big question: do you have to choose one over the other? The answer is a clear no. In fact, they work together remarkably well.&lt;/p&gt;

&lt;p&gt;Ansible is great at telling systems &lt;em&gt;how&lt;/em&gt; to perform a series of tasks. GitOps is a methodology focused on declaring &lt;em&gt;what&lt;/em&gt; the end state should look like, using Git as the single source of truth. Combining them lets you manage everything, from your Kubernetes clusters to your legacy virtual machines, all from a single, version-controlled repository.&lt;/p&gt;

&lt;p&gt;This post will show you how to blend Ansible’s powerful automation with a modern GitOps workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Combine Ansible and GitOps?
&lt;/h2&gt;

&lt;p&gt;Think of it like building a house. GitOps is the architect’s blueprint. It declaratively shows what the finished house should look like—three bedrooms, two bathrooms, a big kitchen. It is the desired state.&lt;/p&gt;

&lt;p&gt;Ansible is the experienced construction crew. They have all the tools and skills to actually build the house based on that blueprint. They pour the foundation, frame the walls, and install the plumbing, handling the specific, step-by-step tasks.&lt;/p&gt;

&lt;p&gt;While GitOps tools like Argo CD and Flux are excellent for managing Kubernetes resources (the blueprint part), they often can't handle tasks outside the cluster. What about provisioning a database on a VM or configuring a network switch? That’s where your Ansible "construction crew" comes in.&lt;/p&gt;

&lt;p&gt;By using them together, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A Single Source of Truth:&lt;/strong&gt; Your Git repo can now describe the state of your &lt;em&gt;entire&lt;/em&gt; infrastructure, not just Kubernetes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reuse Your Existing Work:&lt;/strong&gt; There's no need to throw away all your battle-tested Ansible playbooks and roles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full Infrastructure Management:&lt;/strong&gt; You can manage applications on Kubernetes and traditional systems with the same consistent, auditable workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Make It Work
&lt;/h2&gt;

&lt;p&gt;The key is to trigger your Ansible jobs based on changes in your Git repository. There are two common and effective ways to set this up.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Operator Model (The Kubernetes-Native Way)
&lt;/h3&gt;

&lt;p&gt;This is the most integrated approach if you're working heavily within Kubernetes. It involves using a Kubernetes Operator designed to run Ansible jobs. The Ansible Automation Platform (AAP) Operator is a popular choice, but other open-source options are also available.&lt;/p&gt;

&lt;p&gt;Here’s the flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You commit a change to a YAML file in your Git repository. This file is a &lt;code&gt;CustomResource&lt;/code&gt; that describes the Ansible job you want to run.&lt;/li&gt;
&lt;li&gt;Your GitOps tool (like Argo CD) sees this change and applies the &lt;code&gt;CustomResource&lt;/code&gt; to your cluster.&lt;/li&gt;
&lt;li&gt;The Ansible Operator, which is always watching for these specific resources, sees the new object.&lt;/li&gt;
&lt;li&gt;The Operator spins up a Pod and runs the Ansible playbook you specified.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is what that &lt;code&gt;CustomResource&lt;/code&gt; might look like. It’s a simple, declarative request to run a playbook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ansible-run.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;automation.ansible.com/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AnsibleJob&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;provision-new-vm&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# The playbook to run from your git repo&lt;/span&gt;
  &lt;span class="na"&gt;playbook&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;playbooks/provision-vm.yml"&lt;/span&gt;
  &lt;span class="c1"&gt;# Extra variables to pass to the playbook&lt;/span&gt;
  &lt;span class="na"&gt;extra_vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vm_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;web-server-01"&lt;/span&gt;
    &lt;span class="na"&gt;vm_size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;t2.micro"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you commit this file, the GitOps process kicks off, and your VM gets provisioned automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The CI/CD Pipeline Model (The Simple and Flexible Way)
&lt;/h3&gt;

&lt;p&gt;If you don't want to run an operator inside Kubernetes, or if you're managing non-Kubernetes resources, a standard CI/CD pipeline is a fantastic choice. It's more straightforward and works with tools you already use, like GitHub Actions or GitLab CI.&lt;/p&gt;

&lt;p&gt;The flow is very direct:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You push a change to your Git repository.&lt;/li&gt;
&lt;li&gt;The push triggers a CI/CD pipeline (e.g., a GitHub Actions workflow).&lt;/li&gt;
&lt;li&gt;The pipeline job checks out the repository.&lt;/li&gt;
&lt;li&gt;The job runs the &lt;code&gt;ansible-playbook&lt;/code&gt; command to apply the changes to your infrastructure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s a simple GitHub Actions workflow that runs a playbook on every push to the &lt;code&gt;main&lt;/code&gt; branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/ansible.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Ansible Playbook&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check out code&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Ansible playbook&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dawidd6/action-ansible-playbook@v2&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;playbook&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;site.yml&lt;/span&gt;
        &lt;span class="c1"&gt;# Stored securely in GitHub Secrets&lt;/span&gt;
        &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SSH_PRIVATE_KEY }}&lt;/span&gt;
        &lt;span class="na"&gt;inventory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;[webservers]&lt;/span&gt;
          &lt;span class="s"&gt;app1.example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is less "Kubernetes-native" but is incredibly effective and easy to set up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices to Remember
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep Playbooks Idempotent:&lt;/strong&gt; An idempotent playbook can be run over and over, but it will only make changes the first time to reach the desired state. This is absolutely critical for reliable automation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manage Secrets Properly:&lt;/strong&gt; Never, ever commit secrets like API keys or passwords to Git. Use a dedicated tool like HashiCorp Vault, AWS Secrets Manager, or Ansible Vault to manage them securely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Roles for Reusability:&lt;/strong&gt; Break your playbooks into reusable Ansible Roles. This keeps your code clean, organized, and much easier to maintain as your infrastructure grows.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Ansible and GitOps aren't competitors; they're partners. GitOps defines the "what"—the desired state of your system stored in Git. Ansible provides a powerful "how"—an engine that can make that state a reality across any part of your infrastructure.&lt;/p&gt;

&lt;p&gt;By combining them, you get a robust, version-controlled, and automated system for managing everything. You can finally have one workflow to rule them all.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://muhabbat.dev/post/ansible-and-gitops-a-practical-guide/" rel="noopener noreferrer"&gt;https://muhabbat.dev/post/ansible-and-gitops-a-practical-guide/&lt;/a&gt; on September 30, 2025.&lt;/p&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>automation</category>
      <category>devops</category>
    </item>
    <item>
      <title>7 Core components of Kubernetes every DevOps engineer should know</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Sun, 28 Sep 2025 11:29:37 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/7-core-components-of-kubernetes-every-devops-engineer-should-know-885</link>
      <guid>https://forem.com/muhabbat_dev/7-core-components-of-kubernetes-every-devops-engineer-should-know-885</guid>
      <description>&lt;p&gt;Kubernetes can feel complicated when you first start. It’s a powerful system with a lot of moving parts. But once you understand its core components, it all starts to make sense.&lt;/p&gt;

&lt;p&gt;Think of Kubernetes like a busy restaurant kitchen. The head chef doesn't cook every meal. Instead, they direct a team of specialists who handle different tasks to get the food out. Kubernetes is the head chef for your applications, and its components are the specialists.&lt;/p&gt;

&lt;p&gt;Let's walk through the seven key components that make it all work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Control Plane: The Brain of the Operation
&lt;/h2&gt;

&lt;p&gt;The control plane is the management center. It makes all the decisions about the cluster, like scheduling applications and responding to failures. It’s the head chef and management staff of our restaurant.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. API Server
&lt;/h3&gt;

&lt;p&gt;The API Server is the front desk of the entire operation. Every request to view or change the state of the cluster goes through it. When you use &lt;code&gt;kubectl&lt;/code&gt;, you are talking directly to the API Server. It validates and processes requests, then updates the cluster’s state in &lt;code&gt;etcd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; It’s the head waiter who takes all orders from customers (you) and communicates them to the kitchen staff (other components).&lt;/p&gt;

&lt;p&gt;For example, this simple command asks the API Server for a list of all running pods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. etcd
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;etcd&lt;/code&gt; is the single source of truth for the entire cluster. It’s a simple, reliable key-value store that holds all configuration data and information about the state of the cluster. Everything from pod details to network configurations is stored here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; This is the restaurant's official recipe book and order log. It stores exactly what was ordered and how it should be made. If there's any confusion, everyone checks this book.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Scheduler
&lt;/h3&gt;

&lt;p&gt;The Scheduler’s job is to assign new pods to a worker node. It watches the API Server for newly created pods that have no node assigned. Then, based on resource needs, policies, and node availability, it picks the best node for that pod.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; The scheduler is the person who decides which chef (node) gets which cooking order (pod). It considers factors like how busy each chef is and if they have the right equipment (e.g., a GPU).&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Controller Manager
&lt;/h3&gt;

&lt;p&gt;The Controller Manager is a daemon that runs several controller processes in the background. Each controller is responsible for a specific part of the cluster. For example, the &lt;code&gt;ReplicaSet&lt;/code&gt; controller makes sure the correct number of pods for an application is always running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; It’s the kitchen manager who constantly checks if the orders are being made correctly. If a dish is ruined, the manager tells a chef to make a new one to fulfill the order. It works to make the current state match the desired state.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Worker Nodes: Where the Work Gets Done
&lt;/h2&gt;

&lt;p&gt;Worker nodes are the machines (virtual or physical) that run your applications. They are the kitchen stations where the actual cooking happens. Each worker node contains a few key components.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Kubelet
&lt;/h3&gt;

&lt;p&gt;The Kubelet is an agent that runs on every single worker node. It receives instructions from the control plane via the API Server and makes sure the containers described in the pod specifications are running and healthy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; The Kubelet is the station chef. It gets its orders and ensures the dish (container) is actually on the stove and cooking as specified in the recipe.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Kube Proxy
&lt;/h3&gt;

&lt;p&gt;The Kube Proxy is a network proxy that runs on each node. Its job is to manage network connectivity for pods. It ensures that each pod gets a unique IP address and handles the routing of traffic to the correct pods based on IP addresses and port numbers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; It’s the waiter inside the kitchen who knows exactly which dish goes to which service window. It manages all the internal traffic routes to make sure everything gets where it needs to go.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Pods
&lt;/h3&gt;

&lt;p&gt;A Pod is the smallest and simplest unit in Kubernetes that you create or deploy. It represents a single instance of your application. A Pod can contain one or more containers, but most commonly, it runs just one. These containers share the same network and storage resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; A Pod is the final dish on a plate. The plate (Pod) holds the main item (your application container) and can also hold side items that support it (sidecar containers).&lt;/p&gt;

&lt;p&gt;Here’s a simple YAML file that defines a Pod running a single Nginx container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-pod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.14.2&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you apply this configuration, the Scheduler finds a node, and the Kubelet on that node starts the Nginx container.&lt;/p&gt;

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

&lt;p&gt;Kubernetes isn't magic. It's a system with a clear separation of duties. The control plane acts as the brain, making decisions, while worker nodes do the actual work.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;API Server:&lt;/strong&gt; The front door.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;etcd:&lt;/strong&gt; The source of truth.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Scheduler:&lt;/strong&gt; The decision-maker for placement.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Controller Manager:&lt;/strong&gt; The enforcer of the desired state.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Kubelet:&lt;/strong&gt; The agent on each node.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Kube Proxy:&lt;/strong&gt; The network router.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Pods:&lt;/strong&gt; The actual running applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By understanding these seven components, you’re no longer just using commands. You’re understanding how the system thinks, which is the key to debugging issues and building reliable applications on Kubernetes.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://muhabbat.dev/post/7-core-components-of-kubernetes-every-devops-engineer-should-know" rel="noopener noreferrer"&gt;https://muhabbat.dev/post/7-core-components-of-kubernetes-every-devops-engineer-should-know&lt;/a&gt; on September 28, 2025.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>containers</category>
      <category>k8s</category>
    </item>
    <item>
      <title>Reusable React Components With TypeScript: A Step By Step Guide</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Fri, 26 Sep 2025 20:59:14 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/reusable-react-components-with-typescript-a-step-by-step-guide-2eka</link>
      <guid>https://forem.com/muhabbat_dev/reusable-react-components-with-typescript-a-step-by-step-guide-2eka</guid>
      <description>&lt;p&gt;If you've written any React, you've probably found yourself copying and pasting a chunk of JSX for a button or a card. It works, but soon you have ten slightly different buttons, and changing one means changing all ten. It’s a pain.&lt;/p&gt;

&lt;p&gt;Think of it like LEGOs. You don't create a brand new, unique brick every time you need a 2x4 piece. You just grab one from the box. That's what reusable components are. They are our LEGO bricks for building UIs. And when you add TypeScript, you make sure each brick only connects where it's supposed to.&lt;/p&gt;

&lt;p&gt;This guide will show you how to create these simple, reusable components in React with TypeScript. No fluff, just practical steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Reusability Matters
&lt;/h2&gt;

&lt;p&gt;Writing code that you can reuse is all about being efficient. It follows the &lt;strong&gt;DRY (Don't Repeat Yourself)&lt;/strong&gt; principle. Instead of writing the same button styling and logic in five different places, you write it once in a component and use it everywhere.&lt;/p&gt;

&lt;p&gt;The benefits are straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Easier to Maintain:&lt;/strong&gt; Need to change the button color? You only have to edit one file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent UI:&lt;/strong&gt; Your app looks and feels the same everywhere because you’re using the same core pieces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Development:&lt;/strong&gt; You build faster by composing UIs from existing components instead of starting from scratch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TypeScript adds a layer of safety. It makes sure you pass the right data (props) to your components, catching errors before they even happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Idea A Simple Button Component
&lt;/h2&gt;

&lt;p&gt;Let's start with a basic button. The goal is to create a component that can accept different text and handle a click event.&lt;/p&gt;

&lt;p&gt;First, we define the "shape" of the data our component expects using a TypeScript &lt;code&gt;type&lt;/code&gt; or &lt;code&gt;interface&lt;/code&gt;. These are the component's props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Button.tsx&lt;/span&gt;

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

&lt;span class="c1"&gt;// Define the props our button will accept&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// A function that takes no arguments and returns nothing&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10px 20px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;ButtonProps&lt;/code&gt; tells us that our &lt;code&gt;Button&lt;/code&gt; component &lt;em&gt;must&lt;/em&gt; receive a &lt;code&gt;text&lt;/code&gt; (string) and an &lt;code&gt;onClick&lt;/code&gt; (function) prop.&lt;/p&gt;

&lt;p&gt;Now, we can use it anywhere in our app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;

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

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Saved!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleCancel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Canceled!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Save Changes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSave&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cancel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleCancel&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We just used the same component to create two different buttons with different text and actions. Simple and clean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Components More Flexible
&lt;/h2&gt;

&lt;p&gt;A good reusable component is flexible. Let's add some common features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Different Variants
&lt;/h3&gt;

&lt;p&gt;What if you need a primary button for main actions and a secondary one for less important ones? This is like a t-shirt that comes in different colors. We can add a &lt;code&gt;variant&lt;/code&gt; prop.&lt;/p&gt;

&lt;p&gt;Let's update our &lt;code&gt;ButtonProps&lt;/code&gt; to include an optional &lt;code&gt;variant&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Button.tsx&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Optional prop&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10px 20px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gray&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We used a TypeScript union type &lt;code&gt;'primary' | 'secondary'&lt;/code&gt; to restrict the possible values for &lt;code&gt;variant&lt;/code&gt;. We also set a default value of &lt;code&gt;'primary'&lt;/code&gt; in the component. Now we can easily control the button's appearance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Usage in App.tsx&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Learn More&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleLearnMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Passing Children for Content
&lt;/h3&gt;

&lt;p&gt;Sometimes you need more than just text inside a component. Maybe you want an icon next to the text in a button, or complex content inside a &lt;code&gt;Card&lt;/code&gt;. This is what the &lt;code&gt;children&lt;/code&gt; prop is for.&lt;/p&gt;

&lt;p&gt;Let's build a &lt;code&gt;Card&lt;/code&gt; component that can wrap any content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Card.tsx&lt;/span&gt;

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

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CardProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This special type accepts anything React can render&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;CardProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #ddd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;boxShadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0 2px 4px rgba(0,0,0,0.1)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;React.ReactNode&lt;/code&gt; type is very flexible. Now we can put anything inside our card.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Welcome&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;some&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="nx"&gt;inside&lt;/span&gt; &lt;span class="nx"&gt;our&lt;/span&gt; &lt;span class="nx"&gt;reusable&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Get Started&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Card&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern, called composition, is powerful. You build complex UI by putting simple components inside each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Tips for Great Reusable Components
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Keep them focused.&lt;/strong&gt; A component should do one thing well. A &lt;code&gt;Button&lt;/code&gt; component shouldn't fetch data.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Define clear props.&lt;/strong&gt; Your props are your component's API. Make them easy to understand with TypeScript.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Avoid specific business logic.&lt;/strong&gt; A reusable component should be dumb. It just displays what you give it. Pass functions as props to handle logic.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Think about composition.&lt;/strong&gt; Don't build a massive, all-in-one component. Build small, focused ones and combine them.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Building reusable components isn't a complex architectural decision; it’s a simple habit. It’s about thinking in terms of LEGOs instead of custom-carved parts. By starting with simple components, defining clear props with TypeScript, and focusing on composition, you write code that is cleaner, easier to maintain, and much faster to build with.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Flutter State Management: A Simple Guide to Provider, Riverpod, and Bloc</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Thu, 25 Sep 2025 10:21:50 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/flutter-state-management-a-simple-guide-to-provider-riverpod-and-bloc-1j7</link>
      <guid>https://forem.com/muhabbat_dev/flutter-state-management-a-simple-guide-to-provider-riverpod-and-bloc-1j7</guid>
      <description>&lt;p&gt;When you first start building a Flutter app, managing state feels simple. But as your app grows, passing data between screens can get messy. You end up with code that's hard to read and even harder to debug. This is where state management solutions come in.&lt;/p&gt;

&lt;p&gt;Think of it like organizing a shared kitchen. At first, with just one person, you can leave things anywhere. But when more people start using it, you need a system—labels, shelves, designated areas—to keep things from becoming chaotic.&lt;/p&gt;

&lt;p&gt;In this post, we'll look at three popular systems for Flutter: &lt;strong&gt;Provider&lt;/strong&gt;, &lt;strong&gt;Riverpod&lt;/strong&gt;, and &lt;strong&gt;BLoC&lt;/strong&gt;. We'll use simple examples to see how they work and help you decide which one is right for your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is State Anyway?
&lt;/h2&gt;

&lt;p&gt;In simple terms, &lt;strong&gt;state&lt;/strong&gt; is just data that can change over time. It’s the value of a counter, whether a user is logged in, or the list of items in a shopping cart. When this data changes, your UI needs to update to reflect it.&lt;/p&gt;

&lt;p&gt;Without a proper system, you might find yourself passing data through many layers of widgets that don't even need it, a problem often called "prop drilling." A good state management solution gives you a clean way to access and modify your data from anywhere in your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provider The Simple Starter
&lt;/h2&gt;

&lt;p&gt;Provider is often the first state management tool Flutter developers learn. It’s built on top of Flutter's &lt;code&gt;InheritedWidget&lt;/code&gt; but makes it much easier to use.&lt;/p&gt;

&lt;p&gt;Imagine Provider as a central notice board in an office. Instead of asking every colleague for a piece of information, you just look at the board. Any widget that needs access to the state can get it directly, as long as it's a descendant of where the state is "provided."&lt;/p&gt;

&lt;h3&gt;
  
  
  How Provider Works
&lt;/h3&gt;

&lt;p&gt;You create a model class that holds your state, usually with &lt;code&gt;ChangeNotifier&lt;/code&gt;. Then you use a &lt;code&gt;ChangeNotifierProvider&lt;/code&gt; to make that model available to the widgets below it.&lt;/p&gt;

&lt;p&gt;Here’s a simple counter example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Create the Counter Model&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CounterModel&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;notifyListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// This tells widgets to rebuild&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Provide the Model&lt;/strong&gt;&lt;br&gt;
Wrap a widget high up in your tree (like &lt;code&gt;MaterialApp&lt;/code&gt;) with &lt;code&gt;ChangeNotifierProvider&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;ChangeNotifierProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;create:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;CounterModel&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Use the State&lt;/strong&gt;&lt;br&gt;
Now, any widget within &lt;code&gt;MyApp&lt;/code&gt; can access the &lt;code&gt;CounterModel&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// To display the count&lt;/span&gt;
&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Count: &lt;/span&gt;&lt;span class="si"&gt;${context.watch&amp;lt;CounterModel&amp;gt;().count}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

&lt;span class="c1"&gt;// To call the increment function&lt;/span&gt;
&lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CounterModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Increment'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use Provider:&lt;/strong&gt; It’s great for small to medium apps or when you're just starting. It’s simple to understand and gets the job done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Riverpod The Modern Upgrade
&lt;/h2&gt;

&lt;p&gt;Riverpod was created by the same author as Provider to fix some of its common issues. The biggest difference is that Riverpod is &lt;strong&gt;compile-safe&lt;/strong&gt; and &lt;strong&gt;independent of the widget tree&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This means you get errors at compile time instead of runtime, and you don't need a &lt;code&gt;BuildContext&lt;/code&gt; to access your state. It’s like getting information delivered directly to you via a dedicated messenger instead of having to walk to the central notice board.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Simple Riverpod Example
&lt;/h3&gt;

&lt;p&gt;With Riverpod, you define global "providers" that hold a piece of state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Define a Provider&lt;/strong&gt;&lt;br&gt;
We'll use a &lt;code&gt;StateNotifierProvider&lt;/code&gt;, which is perfect for managing state that can change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Create a Notifier class&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CounterNotifier&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StateNotifier&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;CounterNotifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Initial state is 0&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Create the provider (a global variable)&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;counterProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StateNotifierProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CounterNotifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CounterNotifier&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Set Up Your App&lt;/strong&gt;&lt;br&gt;
Wrap your entire application in a &lt;code&gt;ProviderScope&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProviderScope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Use the State in a Widget&lt;/strong&gt;&lt;br&gt;
To use the provider, you change your &lt;code&gt;StatelessWidget&lt;/code&gt; to a &lt;code&gt;ConsumerWidget&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CounterText&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ConsumerWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WidgetRef&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Rebuilds the widget when the counter changes&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counterProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Count: &lt;/span&gt;&lt;span class="si"&gt;$count&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// In another widget, for the button&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IncrementButton&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ConsumerWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WidgetRef&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Get the notifier and call the increment method&lt;/span&gt;
        &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counterProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Increment'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use Riverpod:&lt;/strong&gt; It’s an excellent choice for new projects of any size. It’s more scalable and less error-prone than Provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  BLoC The Predictable Powerhouse
&lt;/h2&gt;

&lt;p&gt;BLoC (Business Logic Component) is a design pattern that separates your app's business logic from the UI. It's more structured and a bit more complex than Provider or Riverpod.&lt;/p&gt;

&lt;p&gt;Think of BLoC as a strict assembly line. A request (an &lt;strong&gt;Event&lt;/strong&gt;) goes in one end. It's processed according to a set of rules. A result (a &lt;strong&gt;State&lt;/strong&gt;) comes out the other end. This flow is unidirectional and very predictable, which makes it great for testing and managing complex logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  The BLoC Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;UI sends an Event:&lt;/strong&gt; A button press, text input, etc.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;BLoC receives the Event:&lt;/strong&gt; It processes the event and its logic.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;BLoC emits a new State:&lt;/strong&gt; The BLoC updates its state.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;UI rebuilds:&lt;/strong&gt; The UI listens for state changes and rebuilds itself accordingly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  BLoC Counter Example
&lt;/h3&gt;

&lt;p&gt;Using the &lt;code&gt;flutter_bloc&lt;/code&gt; package simplifies this pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Define Events and States&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Events&lt;/span&gt;
&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CounterEvent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IncrementEvent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;CounterEvent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// States (just an int for this simple case)&lt;/span&gt;
&lt;span class="c1"&gt;// For more complex features, this would be a class.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Create the BLoC&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:bloc/bloc.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CounterBloc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Bloc&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CounterEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;CounterBloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Initial state is 0&lt;/span&gt;
    &lt;span class="kd"&gt;on&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IncrementEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Provide and Use the BLoC&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Provide the BLoC at the top of the tree&lt;/span&gt;
&lt;span class="n"&gt;BlocProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;create:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;CounterBloc&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CounterPage&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;

&lt;span class="c1"&gt;// Use BlocBuilder to listen to state changes and rebuild the UI&lt;/span&gt;
&lt;span class="n"&gt;BlocBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CounterBloc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Count: &lt;/span&gt;&lt;span class="si"&gt;$count&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;

&lt;span class="c1"&gt;// Add an event to the BLoC&lt;/span&gt;
&lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CounterBloc&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IncrementEvent&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Increment'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use BLoC:&lt;/strong&gt; BLoC shines in large, complex applications where state logic is intricate and testability is a top priority. It has a steeper learning curve but provides a very robust structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, Which One Should You Choose?
&lt;/h2&gt;

&lt;p&gt;There is no single "best" solution. It depends on your project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Provider:&lt;/strong&gt; Use it for smaller apps or if you're a beginner. It's simple and effective.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Riverpod:&lt;/strong&gt; A great default for most new projects. It’s powerful, flexible, and fixes the main drawbacks of Provider.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;BLoC:&lt;/strong&gt; Choose it for large-scale applications where you need a strict architecture and predictable state changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most important thing is to pick a solution and use it consistently. Start simple, and don’t be afraid to try a different approach as your app and your skills grow.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://muhabbat.dev/post/flutter-state-management-guide-provider-riverpod-bloc" rel="noopener noreferrer"&gt;https://muhabbat.dev/post/flutter-state-management-guide-provider-riverpod-bloc&lt;/a&gt; on September 25, 2025.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
    </item>
    <item>
      <title>The Complete Guide to API Versioning for Developers</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Wed, 24 Sep 2025 14:20:34 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/the-complete-guide-to-api-versioning-for-developers-9l1</link>
      <guid>https://forem.com/muhabbat_dev/the-complete-guide-to-api-versioning-for-developers-9l1</guid>
      <description>&lt;h1&gt;
  
  
  The Complete Guide to API Versioning for Developers
&lt;/h1&gt;

&lt;p&gt;You just shipped a brilliant API update. The code is cleaner, more efficient, and adds a powerful new feature. But a few hours later, the support channels are on fire. An important client's application is crashing because you renamed a field in a JSON response.&lt;/p&gt;

&lt;p&gt;This scenario is a developer's nightmare, and it's precisely the problem API versioning solves. It's the contract between you and your API's consumers that says, "I will not break your application without warning."&lt;/p&gt;

&lt;p&gt;Think of it like a video game update. When a developer releases a major patch that changes game mechanics, they don't force everyone to update immediately. Players can often choose to play on an older version. API versioning gives your users that same control, allowing them to upgrade when they are ready. This guide covers everything you need to know to handle API evolution gracefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why API Versioning is Non-Negotiable
&lt;/h2&gt;

&lt;p&gt;Software is never truly "done." We constantly refactor, add features, and fix bugs. These changes fall into two categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Non-breaking changes:&lt;/strong&gt; These are safe additions. A new, optional field in a response or a completely new endpoint won't break existing clients. They can simply ignore the new stuff.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;V&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Response&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alex"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;V&lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(Non-breaking)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alex"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alex@example.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;New&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;optional&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;field&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Breaking changes:&lt;/strong&gt; These are modifications that will likely cause errors in client applications that haven't been updated.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Changing a field's data type (e.g., an &lt;code&gt;integer&lt;/code&gt; to a &lt;code&gt;string&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  Renaming or removing a field.&lt;/li&gt;
&lt;li&gt;  Adding a new required field to a request.&lt;/li&gt;
&lt;li&gt;  Changing the authentication mechanism.
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;V&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Response&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"firstName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alex"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lastName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Williams"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;V&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(Breaking&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Change)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fullName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alex Williams"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'user'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;removed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;fields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;combined&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Versioning is our strategy for introducing breaking changes without disrupting service for existing users. It’s a core part of building a stable and trustworthy API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four Key API Versioning Strategies
&lt;/h2&gt;

&lt;p&gt;Let's explore the most common methods for implementing versioning, each with its own trade-offs.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. URI Path Versioning
&lt;/h3&gt;

&lt;p&gt;This is the most popular and straightforward approach. The version number is placed directly in the URL.&lt;/p&gt;

&lt;p&gt;It’s like a bookstore organizing its editions on different shelves. The first edition is on the &lt;code&gt;v1&lt;/code&gt; shelf, and the second edition is on the &lt;code&gt;v2&lt;/code&gt; shelf. It's explicit and easy to find.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://api.example.com/v1/users/123
https://api.example.com/v2/users/123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Pros:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Extremely simple and obvious for API consumers.&lt;/li&gt;
&lt;li&gt;  Easy to test different versions directly in a browser or cURL.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Cons:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  It clutters the URI. Purists argue that a URI should represent a resource, and its version is just a representation of that resource.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Query Parameter Versioning
&lt;/h3&gt;

&lt;p&gt;This method involves passing the version number as a query parameter in the URL.&lt;/p&gt;

&lt;p&gt;Think of it like using a filter on a shopping website. The page URL is the same, but adding &lt;code&gt;?color=blue&lt;/code&gt; changes the content you see.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.example.com/users/123?version=1"&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://api.example.com/users/123?api_version=2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Pros:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Simple to implement and use.&lt;/li&gt;
&lt;li&gt;  Doesn't "pollute" the URI path structure.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Cons:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Can be less clean than URI pathing, as query parameters are often used for filtering and pagination. It can be easy to forget to include the version parameter.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Custom Header Versioning
&lt;/h3&gt;

&lt;p&gt;Here, the client specifies the desired API version in a custom HTTP header. The URI remains clean and version-agnostic.&lt;/p&gt;

&lt;p&gt;This is like going to a coffee shop where the main menu is the default, but you can request an "off-menu" item by giving the barista a special code (the header).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.example.com/users/123"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-Version: 2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your server code reads this header to route the request to the correct version's logic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Pros:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Keeps URIs clean and focused on the resource.&lt;/li&gt;
&lt;li&gt;  Avoids cluttering the URI path or query string.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Cons:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Less discoverable. You can't see the version just by looking at the URL.&lt;/li&gt;
&lt;li&gt;  Requires specialized tools like Postman or cURL for testing; not as simple as pasting a URL into a browser.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Media Type Versioning (Content Negotiation)
&lt;/h3&gt;

&lt;p&gt;This is the most technically "correct" RESTful approach. The version is included in the &lt;code&gt;Accept&lt;/code&gt; header as part of a custom media type.&lt;/p&gt;

&lt;p&gt;This is like asking a library for a book (the resource) but specifying you want the &lt;code&gt;application/vnd.shakespeare.v1+text&lt;/code&gt; version (a specific edition and format).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.example.com/users/123"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Accept: application/vnd.example.v1+json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Pros:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Leverages built-in HTTP mechanisms for content negotiation.&lt;/li&gt;
&lt;li&gt;  Allows for versioning individual resources, not just the entire API.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Cons:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  The most complex and least intuitive method for many developers.&lt;/li&gt;
&lt;li&gt;  The syntax is clunky and less user-friendly.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices Beyond the Strategy
&lt;/h2&gt;

&lt;p&gt;Choosing a method is just the first step. A complete versioning plan includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Have a Default Version:&lt;/strong&gt; What happens if a client makes a request without specifying a version? A good practice is to default to your earliest stable version (e.g., &lt;code&gt;v1&lt;/code&gt;) rather than the latest one. This prevents you from accidentally breaking older clients when you release a new version.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Establish a Deprecation Policy:&lt;/strong&gt; You can't support old versions forever. Create a clear policy for sunsetting old versions. Communicate this timeline clearly to your users (e.g., "v1 will be deprecated in 6 months and fully decommissioned in 12 months").&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Communicate Clearly:&lt;/strong&gt; Use a public changelog, developer emails, and API documentation to announce new versions, list breaking changes, and provide migration guides.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Organize Your Code:&lt;/strong&gt; Manage versions cleanly in your codebase. A common pattern in many web frameworks is to organize controllers or handlers by version.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/api/
├── v1/
│   ├── userController.js
│   └── productController.js
└── v2/
    ├── userController.js
    └── productController.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion: Which Strategy is Right for You?
&lt;/h2&gt;

&lt;p&gt;There's no single "best" strategy; the right choice depends on your API's audience and goals.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  For &lt;strong&gt;public APIs&lt;/strong&gt;, &lt;strong&gt;URI Path Versioning&lt;/strong&gt; is often the winner. It's explicit, easy to document, and simple for developers to use and test.&lt;/li&gt;
&lt;li&gt;  For &lt;strong&gt;internal APIs&lt;/strong&gt;, where the client and server teams are in close communication, &lt;strong&gt;Header Versioning&lt;/strong&gt; is a great choice for maintaining clean URIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ultimately, API versioning is about building a predictable and reliable platform. By planning for change from the beginning, you build trust with your users and empower them to innovate on your platform without fear. The most important step is to choose a strategy, document it, and apply it consistently.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://muhabbat.dev/post/the-complete-guide-to-api-versioning-for-developers/" rel="noopener noreferrer"&gt;https://muhabbat.dev/post/the-complete-guide-to-api-versioning-for-developers/&lt;/a&gt; on September 24, 2025.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>api</category>
      <category>restapi</category>
      <category>node</category>
    </item>
    <item>
      <title>Build a Real-Time Chat App with Flutter and Supabase</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Tue, 23 Sep 2025 10:00:24 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/build-a-real-time-chat-app-with-flutter-and-supabase-2m5j</link>
      <guid>https://forem.com/muhabbat_dev/build-a-real-time-chat-app-with-flutter-and-supabase-2m5j</guid>
      <description>&lt;p&gt;Real-time chat is a core feature in many modern applications, from social media to customer support. Building one from scratch can seem complex, but with the right tools, it’s more accessible than you think. In this tutorial, we’ll build a complete chat application using Flutter for the cross-platform frontend and Supabase for a powerful, scalable backend.&lt;/p&gt;

&lt;p&gt;We will walk through setting up your project, creating the user interface, and implementing real-time messaging with Supabase’s powerful PostgreSQL database and Realtime API, with detailed code explanations along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Flutter and Supabase?
&lt;/h2&gt;

&lt;p&gt;Before we dive in, let’s quickly talk about this tech stack. &lt;strong&gt;Flutter&lt;/strong&gt; allows us to build beautiful, natively compiled applications for mobile, web, and desktop from a single codebase. &lt;strong&gt;Supabase&lt;/strong&gt; is an open-source Firebase alternative that provides a suite of backend tools, including a database, authentication, and real-time subscriptions, making it incredibly easy to get started.&lt;/p&gt;

&lt;p&gt;Together, they create a powerful combination for building a feature-rich chat app efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Supabase Backend
&lt;/h2&gt;

&lt;p&gt;The first step is to configure our backend. Supabase makes this process simple.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create a Supabase Project
&lt;/h3&gt;

&lt;p&gt;If you don't have an account, head over to &lt;a href="http://supabase.com" rel="noopener noreferrer"&gt;supabase.com&lt;/a&gt; and sign up. Once you're in, create a new project. Give it a name, generate a secure database password, and choose a region. Your project will be ready in a couple of minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create the &lt;code&gt;messages&lt;/code&gt; Table
&lt;/h3&gt;

&lt;p&gt;Next, we need a table to store our chat messages.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Navigate to the &lt;strong&gt;Table Editor&lt;/strong&gt; in your Supabase dashboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Create a new table&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Name the table &lt;code&gt;messages&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Disable &lt;strong&gt;Row Level Security (RLS)&lt;/strong&gt; for now to make development easier. We can enable it later for production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the following columns:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* `id`: `int8` (primary key, generated automatically).

* `created_at`: `timestamptz` (default value `now()`).

* `content`: `text`.

* `user_id`: `uuid` (to link messages to users, assuming you use Supabase Auth).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  3. Enable Realtime
&lt;/h3&gt;

&lt;p&gt;Supabase Realtime listens for database changes and broadcasts them to connected clients. To enable it for our &lt;code&gt;messages&lt;/code&gt; table:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;strong&gt;Database&lt;/strong&gt; &amp;gt; &lt;strong&gt;Replication&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find your &lt;code&gt;messages&lt;/code&gt; table and enable it for replication.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it for the backend setup. Now let's move to the Flutter app.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building the Flutter Chat App
&lt;/h2&gt;

&lt;p&gt;With the backend ready, we can start building the frontend.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Project Setup and Dependencies
&lt;/h3&gt;

&lt;p&gt;Create a new Flutter project and add the Supabase dependency to your &lt;code&gt;pubspec.yaml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sdk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter&lt;/span&gt;
  &lt;span class="na"&gt;supabase_flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.5.0&lt;/span&gt; &lt;span class="c1"&gt;# Check for the latest version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;flutter pub get&lt;/code&gt; to install the package. Next, initialize Supabase in your &lt;code&gt;main.dart&lt;/code&gt; file. You can find your Project URL and anon key in your Supabase project's &lt;strong&gt;API Settings&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.dart&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:supabase_flutter/supabase_flutter.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Required for async main&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;url:&lt;/span&gt; &lt;span class="s"&gt;'YOUR_SUPABASE_URL'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;anonKey:&lt;/span&gt; &lt;span class="s"&gt;'YOUR_SUPABASE_ANON_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;'Flutter Chat App'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;home:&lt;/span&gt; &lt;span class="n"&gt;ChatPage&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// We will create this next&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Building the Chat Page
&lt;/h3&gt;

&lt;p&gt;Let's create a new file, &lt;code&gt;chat_page.dart&lt;/code&gt;, and build our UI. We'll use a &lt;code&gt;StatefulWidget&lt;/code&gt; to manage the message stream and the text input controller.&lt;/p&gt;

&lt;p&gt;The core of our real-time functionality is the &lt;code&gt;StreamBuilder&lt;/code&gt;. This widget listens to a stream of data and rebuilds its UI whenever new data arrives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// chat_page.dart&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:supabase_flutter/supabase_flutter.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatPage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;_ChatPageState&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_ChatPageState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_ChatPageState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChatPage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_textController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TextEditingController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_messagesStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'messages'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;primaryKey:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;dispose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_textController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_sendMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_textController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;_textController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// For this example, we assume a user is signed in.&lt;/span&gt;
    &lt;span class="c1"&gt;// Replace with your actual user management logic.&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentUser&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ScaffoldMessenger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;showSnackBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SnackBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;content:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'You must be logged in to send a message.'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'messages'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="s"&gt;'content'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;'user_id'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Real-Time Chat'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="n"&gt;Expanded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;StreamBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&amp;gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;stream:&lt;/span&gt; &lt;span class="n"&gt;_messagesStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Error: &lt;/span&gt;&lt;span class="si"&gt;${snapshot.error}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CircularProgressIndicator&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nl"&gt;reverse:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Show newest messages at the bottom&lt;/span&gt;
                  &lt;span class="nl"&gt;itemCount:&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="nl"&gt;itemBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ListTile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                      &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'content'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                      &lt;span class="nl"&gt;subtitle:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                    &lt;span class="p"&gt;);&lt;/span&gt;
                  &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="n"&gt;_MessageComposer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// The input field&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// A helper widget for the message input field&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;_MessageComposer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;padding:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;symmetric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;horizontal:&lt;/span&gt; &lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="n"&gt;Expanded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;controller:&lt;/span&gt; &lt;span class="n"&gt;_textController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="n"&gt;InputDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nl"&gt;hintText:&lt;/span&gt; &lt;span class="s"&gt;'Enter your message...'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nl"&gt;border:&lt;/span&gt; &lt;span class="n"&gt;OutlineInputBorder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nl"&gt;borderRadius:&lt;/span&gt; &lt;span class="n"&gt;BorderRadius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="n"&gt;IconButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;icon:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="n"&gt;_sendMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Understanding the Code
&lt;/h3&gt;

&lt;p&gt;Let's break down the key parts of our &lt;code&gt;ChatPage&lt;/code&gt; widget.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Message Stream
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_messagesStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'messages'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;primaryKey:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Supabase.instance.client.from('messages')&lt;/code&gt;: This targets our &lt;code&gt;messages&lt;/code&gt; table in the Supabase database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.stream(primaryKey: ['id'])&lt;/code&gt;: This is the magic function. It creates a WebSocket connection to Supabase and listens for any changes (inserts, updates, deletes) in the &lt;code&gt;messages&lt;/code&gt; table. The &lt;code&gt;primaryKey&lt;/code&gt; is required for Supabase to efficiently track changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.order('created_at')&lt;/code&gt;: We sort the messages by their creation timestamp to ensure they are displayed in the correct order.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  The &lt;code&gt;StreamBuilder&lt;/code&gt; Widget
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;StreamBuilder&lt;/code&gt; connects our UI to the &lt;code&gt;_messagesStream&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;StreamBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&amp;gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;stream:&lt;/span&gt; &lt;span class="n"&gt;_messagesStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... handle loading, error, and data states&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;stream&lt;/code&gt;: We pass our &lt;code&gt;_messagesStream&lt;/code&gt; here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;builder&lt;/code&gt;: This function is called every time a new event arrives on the stream. The &lt;code&gt;snapshot&lt;/code&gt; object contains the latest data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;State Handling&lt;/strong&gt;: We check &lt;code&gt;snapshot.hasData&lt;/code&gt; to see if we have messages. If not, we show a loading indicator. If there's an error, we display it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Displaying Data&lt;/strong&gt;: When data is available (&lt;a href="http://snapshot.data" rel="noopener noreferrer"&gt;&lt;code&gt;snapshot.data&lt;/code&gt;&lt;/a&gt;&lt;code&gt;!&lt;/code&gt;), we use a &lt;code&gt;ListView.builder&lt;/code&gt; to efficiently render the list of messages.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Sending a Message
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;_sendMessage&lt;/code&gt; function handles the logic for sending a new message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_sendMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_textController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Don't send empty messages&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;_textController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Get current user's ID&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentUser&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Insert the new message into the database&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'messages'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="s"&gt;'content'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'user_id'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We get the text from our &lt;code&gt;_textController&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We perform a database &lt;strong&gt;insert&lt;/strong&gt; operation on the &lt;code&gt;messages&lt;/code&gt; table.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once the new row is inserted, Supabase's Realtime feature automatically detects this change and broadcasts it to all connected clients.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Our &lt;code&gt;StreamBuilder&lt;/code&gt; receives the new data and instantly rebuilds the UI to show the new message. No manual state management (&lt;code&gt;setState&lt;/code&gt;) is needed for the message list!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;We've successfully built a functional, real-time chat application using Flutter and Supabase. We went from setting up a Supabase project and database table to building a complete Flutter UI that sends and receives messages in real-time. The magic lies in Supabase's stream functionality and Flutter's &lt;code&gt;StreamBuilder&lt;/code&gt; widget, which together handle all the complexity of real-time data synchronization.&lt;/p&gt;

&lt;p&gt;This is just the beginning. You can expand this project by implementing a full authentication flow with Supabase Auth, adding user profiles, displaying usernames next to messages, and enabling Row Level Security for a production-ready application. The combination of Flutter and Supabase provides a powerful and efficient foundation for building modern, scalable apps.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://muhabbat.dev/post/build-a-real-time-chat-app-with-flutter-and-supabase/" rel="noopener noreferrer"&gt;https://muhabbat.dev/post/build-a-real-time-chat-app-with-flutter-and-supabase/&lt;/a&gt; &lt;em&gt;on September 17, 2025.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>supabase</category>
      <category>dart</category>
    </item>
    <item>
      <title>Unlock PostgreSQL Performance: A Practical Tuning Guide</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Tue, 23 Sep 2025 09:53:27 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/unlock-postgresql-performance-a-practical-tuning-guide-ne9</link>
      <guid>https://forem.com/muhabbat_dev/unlock-postgresql-performance-a-practical-tuning-guide-ne9</guid>
      <description>&lt;p&gt;Is your application slowing down? Often, the bottleneck isn't the code but a poorly tuned PostgreSQL database. PostgreSQL is an incredibly powerful and reliable database, but its default configuration is designed for broad compatibility, not peak performance. To get the most out of it, you need to tailor it to your specific workload.&lt;/p&gt;

&lt;p&gt;This guide moves beyond the basics and gives you practical, advanced techniques to diagnose issues and boost your database speed. We’ll cover everything from smart indexing to essential maintenance routines that keep your database running smoothly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Core of PostgreSQL Performance
&lt;/h2&gt;

&lt;p&gt;Before we dive into specific tips, it’s helpful to know what’s happening under the hood. PostgreSQL performance largely depends on how efficiently it can find and process data. Three key areas govern this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Query Planner:&lt;/strong&gt; This is the brain of your database. When you run a query, the planner evaluates different ways to execute it and chooses the one it estimates will be the fastest. Your job is to give it the right information and tools (like indexes) to make the best choice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory Management:&lt;/strong&gt; PostgreSQL uses memory to cache data and execute operations like sorting and joining. Properly configured memory settings ensure that frequently accessed data is served from fast RAM instead of slow disks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database Maintenance:&lt;/strong&gt; Over time, databases can become fragmented or have outdated statistics. Regular maintenance keeps everything organized and ensures the query planner has accurate information.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Essential Tuning Techniques You Can Implement Today
&lt;/h2&gt;

&lt;p&gt;Let's get into the actionable steps. These techniques will provide the biggest improvements in your PostgreSQL performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Master Your Indexing Strategy
&lt;/h3&gt;

&lt;p&gt;Indexes are the single most effective tool for speeding up read queries. But simply adding an index to every column is a bad idea, as it slows down write operations (&lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;). The key is to be strategic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use&lt;/strong&gt; &lt;code&gt;EXPLAIN&lt;/code&gt; to find slow queries: Identify queries that perform a &lt;strong&gt;Sequential Scan&lt;/strong&gt; on a large table. This is often a sign that you need an index.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Go beyond the B-Tree:&lt;/strong&gt; The default B-tree index is great for equality and range queries (&lt;code&gt;=&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;). But PostgreSQL offers more specialized index types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GIN (Generalized Inverted Index):&lt;/strong&gt; Ideal for indexing array elements or full-text search.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GiST (Generalized Search Tree):&lt;/strong&gt; Useful for indexing geometric data and full-text search.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partial Indexes:&lt;/strong&gt; This is a powerful feature. A partial index only covers a subset of rows in a table, defined by a &lt;code&gt;WHERE&lt;/code&gt; clause. This results in smaller, faster indexes. For example, if you frequently query for active users, you can create an index just for them: &lt;code&gt;CREATE INDEX idx_users_active ON users (id) WHERE status = 'active';&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Analyze and Optimize Your Queries with EXPLAIN
&lt;/h3&gt;

&lt;p&gt;You can't fix what you can't measure. The &lt;code&gt;EXPLAIN&lt;/code&gt; command is your window into the query planner. It shows you exactly how PostgreSQL intends to execute your query.&lt;/p&gt;

&lt;p&gt;To get even more detail, use &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt;. This command actually runs the query and gives you the real execution time and row counts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to read the output:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Look for &lt;strong&gt;Sequential Scans&lt;/strong&gt; on large tables. This means PostgreSQL is reading the entire table to find the data it needs. An &lt;strong&gt;Index Scan&lt;/strong&gt; is usually much faster.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check the &lt;code&gt;cost&lt;/code&gt;. This is the planner's estimate of how much work the query will take. Your goal is to reduce this number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pay attention to the &lt;code&gt;rows&lt;/code&gt; estimate versus the actual &lt;code&gt;rows&lt;/code&gt; returned by &lt;code&gt;ANALYZE&lt;/code&gt;. A large difference suggests the database statistics are out of date.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Configure Your Memory Settings Wisely
&lt;/h3&gt;

&lt;p&gt;Tuning PostgreSQL's memory settings can dramatically reduce disk I/O. You'll make these changes in your &lt;code&gt;postgresql.conf&lt;/code&gt; file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;shared_buffers&lt;/code&gt;: This is the most important memory setting. It defines how much memory PostgreSQL can use for its data cache. A good starting point is &lt;strong&gt;25% of your system's RAM&lt;/strong&gt;. Don't set it too high, as you need to leave memory for the operating system and other processes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;work_mem&lt;/code&gt;: This setting controls the memory used for sorting, hashing, and merging. If your queries involve complex sorts or joins that spill to disk, increasing &lt;code&gt;work_mem&lt;/code&gt; can help. But be careful; this memory can be allocated per operation, so a high value with many concurrent connections can quickly exhaust your RAM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;maintenance_work_mem&lt;/code&gt;: This is the memory used for maintenance tasks like &lt;code&gt;VACUUM&lt;/code&gt; and &lt;code&gt;CREATE INDEX&lt;/code&gt;. Setting this higher can significantly speed up these operations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Don't Forget Database Maintenance
&lt;/h3&gt;

&lt;p&gt;A well-oiled machine needs regular upkeep. For PostgreSQL, this means running &lt;code&gt;VACUUM&lt;/code&gt; and &lt;code&gt;ANALYZE&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;VACUUM&lt;/code&gt;: Recovers space occupied by dead rows (rows that were updated or deleted). The autovacuum daemon handles this automatically, but you may need to tune its settings for heavily updated tables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ANALYZE&lt;/code&gt;: Collects statistics about the data distribution in your tables. The query planner uses these statistics to make smart decisions. Out-of-date stats can lead to poor query plans.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Table Bloat&lt;/strong&gt;: If tables are constantly updated and deleted, they can become "bloated" with empty space. While regular &lt;code&gt;VACUUM&lt;/code&gt; helps, you might occasionally need to run &lt;code&gt;VACUUM FULL&lt;/code&gt; to reclaim all the space. &lt;strong&gt;Warning:&lt;/strong&gt; &lt;code&gt;VACUUM FULL&lt;/code&gt; locks the table, so run it during a maintenance window.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;PostgreSQL performance tuning isn't a one-time fix; it's an ongoing process of monitoring and refining. By focusing on the core pillars of indexing, query analysis, memory configuration, and regular maintenance, you can transform a slow database into a highly responsive one.&lt;/p&gt;

&lt;p&gt;Start by identifying your slowest queries with tools like &lt;code&gt;pg_stat_statements&lt;/code&gt;, use &lt;code&gt;EXPLAIN&lt;/code&gt; to understand their behavior, and apply the techniques in this guide. Your users, and your servers, will thank you for it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://muhabbat.dev/post/unlock-postgresql-performance-a-practical-tuning-guide/" rel="noopener noreferrer"&gt;https://muhabbat.dev/post/unlock-postgresql-performance-a-practical-tuning-guide/&lt;/a&gt; &lt;em&gt;on September 18, 2025.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>mysql</category>
      <category>database</category>
      <category>postgressql</category>
    </item>
    <item>
      <title>Mastering Flutter BLoC A Practical Guide</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Tue, 23 Sep 2025 09:49:22 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/mastering-flutter-bloc-a-practical-guide-97j</link>
      <guid>https://forem.com/muhabbat_dev/mastering-flutter-bloc-a-practical-guide-97j</guid>
      <description>&lt;p&gt;State management is a critical part of any Flutter application. As your app grows, managing how data flows can get complicated. This is where a solid architectural pattern comes in, and for many Flutter developers, BLoC is the answer.&lt;/p&gt;

&lt;p&gt;The BLoC (Business Logic Component) pattern helps separate your app's business logic from its UI, leading to code that is easier to test, maintain, and scale. But just knowing about BLoC isn’t enough. Using it effectively is what makes the difference. This guide will walk you through a practical, code-heavy example to help you master the Flutter BLoC pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is BLoC and Why Use It
&lt;/h2&gt;

&lt;p&gt;At its core, the BLoC pattern is a way to handle state in an application. It works by taking events from the UI, processing them in the business logic layer, and emitting new states back to the UI. The UI then rebuilds itself based on the new state.&lt;/p&gt;

&lt;p&gt;The main benefits of using BLoC are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Separation of Concerns:&lt;/strong&gt; Your UI code only cares about rendering states and dispatching events. Your business logic is contained entirely within the BLoC, making it independent of the UI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testability:&lt;/strong&gt; With business logic isolated, you can write unit tests for your BLoCs without needing to render any UI components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; As your app grows, BLoC provides a clear and predictable way to manage state, preventing your codebase from becoming a tangled mess.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Complete BLoC Example: Authentication Flow
&lt;/h2&gt;

&lt;p&gt;Let's build a simple authentication feature to see how all the pieces of BLoC fit together. We'll cover defining events and states, implementing the BLoC, and connecting it to the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Defining States
&lt;/h3&gt;

&lt;p&gt;First, we define the possible states our authentication feature can be in. A good approach is to use an abstract base class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:equatable/equatable.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Equatable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AuthState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The initial state, before any user interaction&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthInitial&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AuthState&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// The state when authentication is in progress&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthLoading&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AuthState&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// The state when the user is successfully authenticated&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthSuccess&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AuthState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Example data&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AuthSuccess&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userToken&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;userToken&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The state when authentication fails&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthFailure&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AuthState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AuthFailure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Defining Events
&lt;/h3&gt;

&lt;p&gt;Next, we define the events that the UI can send to the BLoC to trigger state changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:equatable/equatable.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthEvent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Equatable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AuthEvent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Event triggered when the user tries to log in&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthLoginRequested&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AuthEvent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AuthLoginRequested&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Event triggered when the user logs out&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthLogoutRequested&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AuthEvent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Implementing the BLoC
&lt;/h3&gt;

&lt;p&gt;Now we create the &lt;code&gt;AuthBloc&lt;/code&gt; itself. It will listen for &lt;code&gt;AuthEvent&lt;/code&gt;s and emit &lt;code&gt;AuthState&lt;/code&gt;s in response. This is where your business logic lives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_bloc/flutter_bloc.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Import your event and state files&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthBloc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Bloc&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AuthState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// You would typically inject a repository or service here&lt;/span&gt;
  &lt;span class="c1"&gt;// final AuthRepository authRepository;&lt;/span&gt;

  &lt;span class="n"&gt;AuthBloc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthInitial&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;on&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthLoginRequested&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;_onLoginRequested&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;on&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthLogoutRequested&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;_onLogoutRequested&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_onLoginRequested&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;AuthLoginRequested&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Emitter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthLoading&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Simulate a network call&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;seconds:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'test@test.com'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'fake-jwt-token'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AuthSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;userToken:&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="s"&gt;'Invalid credentials'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthFailure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;error:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_onLogoutRequested&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;AuthLogoutRequested&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Emitter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Clear user session, etc.&lt;/span&gt;
    &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthInitial&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Connecting BLoC to the UI
&lt;/h3&gt;

&lt;p&gt;To use our &lt;code&gt;AuthBloc&lt;/code&gt;, we first need to provide it to our widget tree using &lt;code&gt;BlocProvider&lt;/code&gt;. This is often done at the root of your app or the top of the relevant feature screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.dart or a similar entry point&lt;/span&gt;
&lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;BlocProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;create:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;AuthBloc&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, within our UI, we can use &lt;code&gt;BlocBuilder&lt;/code&gt; to listen for state changes and rebuild widgets, and &lt;code&gt;BlocListener&lt;/code&gt; for one-time actions like navigation or showing a snackbar. A great widget that combines both is &lt;code&gt;BlocConsumer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's see it in a login page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginPage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;LoginPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;emailController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TextEditingController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;passwordController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TextEditingController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Login'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;BlocConsumer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthBloc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AuthState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;listener:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Listener for side-effects&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;AuthFailure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ScaffoldMessenger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hideCurrentSnackBar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;showSnackBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;SnackBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;content:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
              &lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;AuthSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Navigate to home screen on success&lt;/span&gt;
            &lt;span class="n"&gt;Navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pushReplacementNamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/home'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Builder for rebuilding UI&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;AuthLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CircularProgressIndicator&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;

          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;padding:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;16.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="n"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nl"&gt;controller:&lt;/span&gt; &lt;span class="n"&gt;emailController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;InputDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;labelText:&lt;/span&gt; &lt;span class="s"&gt;'Email'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nl"&gt;controller:&lt;/span&gt; &lt;span class="n"&gt;passwordController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="nl"&gt;obscureText:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;InputDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;labelText:&lt;/span&gt; &lt;span class="s"&gt;'Password'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SizedBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Add the login event to the BLoC&lt;/span&gt;
                    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthBloc&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                          &lt;span class="n"&gt;AuthLoginRequested&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nl"&gt;email:&lt;/span&gt; &lt;span class="n"&gt;emailController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="nl"&gt;password:&lt;/span&gt; &lt;span class="n"&gt;passwordController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="p"&gt;);&lt;/span&gt;
                  &lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Login'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example shows the full loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The UI dispatches an &lt;code&gt;AuthLoginRequested&lt;/code&gt; event when the button is pressed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;AuthBloc&lt;/code&gt; receives the event, emits an &lt;code&gt;AuthLoading&lt;/code&gt; state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;BlocConsumer&lt;/code&gt; rebuilds the UI to show a loading indicator.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The BLoC finishes its logic and emits either &lt;code&gt;AuthSuccess&lt;/code&gt; or &lt;code&gt;AuthFailure&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;BlocConsumer&lt;/code&gt;'s &lt;code&gt;listener&lt;/code&gt; triggers a navigation or a snackbar, and the &lt;code&gt;builder&lt;/code&gt; updates the UI if needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;The BLoC pattern can seem complex, but breaking it down into events, states, and the BLoC itself makes it manageable. By creating a clear, unidirectional flow of data, you can build applications that are robust, testable, and easy to scale.&lt;/p&gt;

&lt;p&gt;The key takeaway is to let events drive your logic and states drive your UI. By fully embracing this separation, you'll be well on your way to mastering state management in your Flutter projects and writing cleaner, more maintainable code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://muhabbat.dev/post/mastering-flutter-bloc-a-practical-guide/" rel="noopener noreferrer"&gt;&lt;em&gt;https://muhabbat.dev&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on September 19, 2025.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>android</category>
    </item>
    <item>
      <title>A Developer's Guide to Cloud Computing</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Tue, 23 Sep 2025 09:44:46 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/a-developers-guide-to-cloud-computing-5511</link>
      <guid>https://forem.com/muhabbat_dev/a-developers-guide-to-cloud-computing-5511</guid>
      <description>&lt;p&gt;Remember the days of FTPing files to a shared hosting server? Or waiting weeks for IT to provision a new physical server for your project? As developers, we've come a long way. The force behind this massive shift in how we build, deploy, and scale applications is cloud computing.&lt;/p&gt;

&lt;p&gt;If you still think of "the cloud" as just someone else's computer, you're missing the bigger picture. The cloud isn't just about hosting; it's a powerful toolkit that provides on-demand infrastructure, managed services, and powerful APIs that have become essential for modern software development. This guide breaks down what cloud computing really means for you, the developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Cloud Computing from a Coder's Perspective
&lt;/h2&gt;

&lt;p&gt;At its core, cloud computing is about &lt;strong&gt;abstracting infrastructure&lt;/strong&gt;. Instead of dealing with physical servers, networking hardware, and storage arrays, you interact with these resources through APIs. Need a new Linux instance? A few lines of code or a single CLI command can spin one up in seconds. Need a scalable database? You can provision one without ever touching a server rack.&lt;/p&gt;

&lt;p&gt;This paradigm shift allows developers to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Focus on code, not hardware:&lt;/strong&gt; Let cloud providers like AWS, Azure, and GCP manage the physical infrastructure, so you can focus on building features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automate everything:&lt;/strong&gt; Treat your infrastructure as code (IaC) using tools like Terraform or AWS CloudFormation to create reproducible and version-controlled environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pay for what you use:&lt;/strong&gt; Move from large capital expenditures (buying servers) to operational expenses (paying for compute time), making it easier to experiment and scale.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Cloud Service Models A Developer's Breakdown
&lt;/h2&gt;

&lt;p&gt;The old "pizza-as-a-service" analogy is fine for beginners, but for developers, it’s more useful to think about the service models in terms of control and responsibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure as a Service (IaaS)
&lt;/h3&gt;

&lt;p&gt;IaaS gives you the raw ingredients of cloud infrastructure: virtual machines, storage, and networking. You have maximum control over the operating system, runtime, and application configuration.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; You're renting virtual servers (like &lt;strong&gt;Amazon EC2&lt;/strong&gt; or &lt;strong&gt;Azure VMs&lt;/strong&gt;). You're responsible for installing software, managing security patches, and configuring the environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you need fine-grained control over the environment.&lt;/li&gt;
&lt;li&gt;For lifting and shifting legacy applications to the cloud.&lt;/li&gt;
&lt;li&gt;When you have very specific OS or software requirements that a PaaS doesn't support.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Platform as a Service (PaaS)
&lt;/h3&gt;

&lt;p&gt;PaaS abstracts away the underlying OS and infrastructure management, providing a platform for you to deploy and manage applications. This is where many developers find the sweet spot between control and convenience.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; You bring your code, and the platform handles the rest—deployment, load balancing, scaling, and OS updates. Think &lt;code&gt;git push heroku main&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For rapid development and deployment of web apps and APIs.&lt;/li&gt;
&lt;li&gt;When you want to focus entirely on application code and not on server management.&lt;/li&gt;
&lt;li&gt;Ideal for building cloud-native applications.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt; &lt;strong&gt;Heroku&lt;/strong&gt;, &lt;strong&gt;AWS Elastic Beanstalk&lt;/strong&gt;, &lt;strong&gt;Google App Engine&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Software as a Service (SaaS) and APIs
&lt;/h3&gt;

&lt;p&gt;While end-users see SaaS as ready-to-use software (like Gmail or Slack), developers see SaaS as a collection of powerful, third-party APIs they can integrate into their applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What it is for developers:&lt;/strong&gt; Instead of building complex features from scratch, you use a specialized service via its API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Payments:&lt;/strong&gt; Integrate with &lt;strong&gt;Stripe&lt;/strong&gt; instead of building a PCI-compliant payment gateway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication:&lt;/strong&gt; Use &lt;strong&gt;Auth0&lt;/strong&gt; or &lt;strong&gt;Okta&lt;/strong&gt; instead of rolling your own user management system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communications:&lt;/strong&gt; Leverage &lt;strong&gt;Twilio&lt;/strong&gt; for SMS and voice capabilities.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why the Cloud is a Game Changer for Development
&lt;/h2&gt;

&lt;p&gt;Adopting the cloud is about more than just cost savings; it fundamentally improves the entire software development lifecycle.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Accelerated Development:&lt;/strong&gt; Spin up databases, message queues, and full environments in minutes. No more waiting for hardware.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Effortless Scalability:&lt;/strong&gt; Is your app featured on a major blog? Auto-scaling groups can automatically add more server instances to handle the load and scale back down when traffic subsides.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Power of Managed Services:&lt;/strong&gt; Offload tedious operational tasks. Use &lt;strong&gt;Amazon RDS&lt;/strong&gt; or &lt;strong&gt;Azure SQL Database&lt;/strong&gt; to get a fully managed, patched, and backed-up database without ever needing to SSH into a server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enabling DevOps and CI/CD:&lt;/strong&gt; The cloud is the foundation of modern DevOps. Services like &lt;strong&gt;AWS CodePipeline&lt;/strong&gt;, &lt;strong&gt;Azure DevOps&lt;/strong&gt;, and &lt;strong&gt;GitHub Actions&lt;/strong&gt; leverage cloud infrastructure to automate building, testing, and deploying your code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Cloud Technologies Every Developer Should Know
&lt;/h2&gt;

&lt;p&gt;To be effective in a cloud environment, you need to be familiar with a few core concepts that have become industry standards.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Containers (Docker &amp;amp; Kubernetes)
&lt;/h3&gt;

&lt;p&gt;Containers solve the classic "it works on my machine" problem. &lt;strong&gt;Docker&lt;/strong&gt; packages your application and all its dependencies into a single, isolated container. &lt;strong&gt;Kubernetes&lt;/strong&gt; then takes over, allowing you to run and manage these containers at scale across a cluster of machines.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Serverless Computing (FaaS)
&lt;/h3&gt;

&lt;p&gt;Serverless, or Functions-as-a-Service (FaaS), takes abstraction a step further. You upload your code as individual functions (&lt;strong&gt;AWS Lambda&lt;/strong&gt;, &lt;strong&gt;Google Cloud Functions&lt;/strong&gt;, &lt;strong&gt;Azure Functions&lt;/strong&gt;), and the cloud provider handles everything about executing it. You don't manage any servers, and you only pay for the milliseconds your code is actually running. It's perfect for event-driven architectures and APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Infrastructure as Code (IaC)
&lt;/h3&gt;

&lt;p&gt;IaC is the practice of managing and provisioning your infrastructure using code and configuration files. Tools like &lt;strong&gt;Terraform&lt;/strong&gt; and &lt;strong&gt;AWS CloudFormation&lt;/strong&gt; allow you to define your entire cloud stack—servers, databases, networks—in version-controlled files. This makes your infrastructure predictable, repeatable, and easy to tear down or replicate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Next Steps in the Cloud
&lt;/h2&gt;

&lt;p&gt;Cloud computing is no longer optional for developers; it’s a core competency. It provides a powerful set of tools that enable you to build more resilient, scalable, and innovative applications faster than ever before.&lt;/p&gt;

&lt;p&gt;If you're just getting started, the best way to learn is by doing. All major providers (&lt;strong&gt;AWS&lt;/strong&gt;, &lt;strong&gt;Azure&lt;/strong&gt;, and &lt;strong&gt;GCP&lt;/strong&gt;) offer generous free tiers. Pick one, think of a small project, and try deploying it using a PaaS solution or a serverless function. Your journey to becoming a cloud-native developer starts today.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://muhabbat.dev/post/a-developers-guide-to-cloud-computing/%C2%A0on" rel="noopener noreferrer"&gt;https://muhabbat.dev/post/a-developers-guide-to-cloud-computing/ on&lt;/a&gt; September 21, 2025.&lt;/p&gt;

</description>
      <category>cloudcomputing</category>
      <category>devops</category>
      <category>googlecloud</category>
      <category>aws</category>
    </item>
    <item>
      <title>Unlocking Claude: A Developer's Guide to Effective AI Prompting</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Tue, 23 Sep 2025 09:32:19 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/unlocking-claude-a-developers-guide-to-effective-ai-prompting-3d21</link>
      <guid>https://forem.com/muhabbat_dev/unlocking-claude-a-developers-guide-to-effective-ai-prompting-3d21</guid>
      <description>&lt;p&gt;You ask your AI assistant, Claude, to write a simple function. It gives you something that looks right but breaks on the first edge case. Or you ask it to explain a complex topic, and you get a generic, textbook answer. Sound familiar?&lt;/p&gt;

&lt;p&gt;Many developers treat AI tools like a search engine, firing off simple questions and hoping for the best. But Claude is a powerful collaborator, not just a snippet generator. The difference between a frustrating experience and a productive one comes down to a single skill: how you write your prompts.&lt;/p&gt;

&lt;p&gt;This guide will show you how to move from basic questions to expert-level prompts that get you the code, explanations, and architectural insights you actually need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Your Claude Prompts Aren't Working
&lt;/h2&gt;

&lt;p&gt;From a code perspective, the logic is simple: the output of a system is only as good as its input. This is especially true for AI. If a prompt is unclear or lacks critical details, Claude has to make assumptions. These assumptions often lead to generic code, incorrect logic, or incomplete solutions. Most ineffective prompts stem from a few common mistakes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vague Requests:&lt;/strong&gt; Asking Claude to "write a login function" is too broad. It has no information about the language, framework, database, or authentication method you're using.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of Context:&lt;/strong&gt; Without seeing your existing code, database schema, or project requirements, the AI is just guessing. It can't know you prefer functional components in React or that your API needs to follow a specific JSON structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No Defined Output:&lt;/strong&gt; You want code, but do you also want comments? Unit tests? An explanation of how it works? If you don't specify the desired output, you'll get a default response that might not be what you need.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Core Principles of Effective Prompting for Developers
&lt;/h2&gt;

&lt;p&gt;To get expert-level results, you need to think like a senior developer giving instructions to a junior pair programmer. Be clear, be specific, and provide all the necessary information upfront.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Provide Rich Context
&lt;/h3&gt;

&lt;p&gt;Context is the most critical element of a good prompt. The more relevant details you provide, the more tailored and accurate Claude’s response will be. Always include the "what, why, and how" in your request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Write a Python function to fetch user data."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I'm using &lt;strong&gt;Python with the FastAPI framework&lt;/strong&gt; and a PostgreSQL database with SQLAlchemy. Here is my SQLAlchemy model for the &lt;code&gt;User&lt;/code&gt; table:&lt;/p&gt;


&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;users&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
   &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Write an &lt;strong&gt;asynchronous FastAPI path operation function&lt;/strong&gt; to fetch a user by their ID. It should handle the case where the user is not found by &lt;strong&gt;raising a 404 HTTPException&lt;/strong&gt; and return the user data."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second prompt gives Claude the tech stack, existing code, and specific error handling requirements, leading to a much more useful and integrated solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Assign a Persona
&lt;/h3&gt;

&lt;p&gt;Tell Claude &lt;em&gt;who&lt;/em&gt; it should be. Assigning a role frames the conversation and influences the tone, style, and depth of the response. This helps it adopt the correct mindset for the task.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;"Act as a &lt;strong&gt;senior software architect specializing in microservices&lt;/strong&gt;..." for system design questions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"You are a &lt;strong&gt;cybersecurity expert&lt;/strong&gt;. Review the following Python code for potential security vulnerabilities like SQL injection or XSS."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Behave as a &lt;strong&gt;patient tutor&lt;/strong&gt;. Explain the concept of closures in JavaScript to someone who only knows object-oriented programming."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Define the Output Structure
&lt;/h3&gt;

&lt;p&gt;Don't leave the format to chance. Tell Claude exactly how you want the information presented. This is especially useful for generating structured data, documentation, or test cases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;"Provide the output as a &lt;strong&gt;JSON object&lt;/strong&gt; with the keys &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;data&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt;."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Explain the pros and cons of using WebSockets versus server-sent events in a &lt;strong&gt;Markdown table&lt;/strong&gt;."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Generate the function and then add a separate block with &lt;strong&gt;three unit tests&lt;/strong&gt; for it using the &lt;code&gt;pytest&lt;/code&gt; framework."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Iterate and Refine
&lt;/h3&gt;

&lt;p&gt;Your first prompt is the start of a conversation, not the end. Use follow-up questions to refine the output until it’s perfect.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;"That’s a good start. Can you add JSDoc comments to the function?"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Now refactor that code to make it more readable."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"What are the performance implications of this approach?"&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced Prompting Techniques
&lt;/h2&gt;

&lt;p&gt;Once you've mastered the basics, you can use Claude for much more than just writing small functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Claude for System Design
&lt;/h3&gt;

&lt;p&gt;Feed Claude a set of requirements and ask for architectural suggestions. It's a fantastic brainstorming partner for exploring different approaches before you commit to one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Prompt:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I need to design a scalable notification system for a social media app. Key requirements are real-time delivery, support for push and email notifications, and the ability to handle millions of users. Suggest a high-level architecture using AWS services and explain the role of each component (e.g., SQS, Lambda, SNS)."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Code Debugging and Refactoring
&lt;/h3&gt;

&lt;p&gt;Instead of staring at a bug for an hour, paste the problematic code into Claude and ask for help. Provide the error message and any relevant context for the best results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Prompt:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Here is a piece of JavaScript that is supposed to filter an array of objects, but it's returning an empty array.&lt;/p&gt;


&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// [code snippet]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The error I'm seeing is &lt;code&gt;TypeError: cannot read properties of undefined&lt;/code&gt;. Can you identify the bug and suggest a fix?"&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Claude isn't here to replace developers; it's a tool to augment our skills. By moving away from simple, search-like queries and adopting a more deliberate, context-rich approach to prompting, you can transform your AI assistant from a simple code generator into a true development partner.&lt;/p&gt;

&lt;p&gt;The key is to treat it like a technical conversation. Provide context, define your expectations, and iterate. Start applying these principles today, and you'll quickly see the difference in the quality and relevance of the results.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>developer</category>
      <category>llm</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Can React Context Really Replace Redux or Zustand</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Mon, 22 Sep 2025 22:00:00 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/can-react-context-really-replace-redux-or-zustand-4e29</link>
      <guid>https://forem.com/muhabbat_dev/can-react-context-really-replace-redux-or-zustand-4e29</guid>
      <description>&lt;p&gt;As a developer, you’ve probably asked this question. With every new React project, we face the big decision: how should we manage state? For a long time, Redux was the default answer. Then came Context API, built right into React, and many wondered if we even needed external libraries anymore.&lt;/p&gt;

&lt;p&gt;The short answer is: &lt;strong&gt;no, Context does not replace Redux or Zustand.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But the long answer is more interesting. They solve different problems. Thinking of it as a competition is the wrong way to look at it. Instead, let's figure out which tool is right for which job. This post will break it down with simple examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Prop Drilling
&lt;/h2&gt;

&lt;p&gt;Before we compare tools, let's remember the problem we're trying to solve. In a React app, you often need to pass data from a top-level component to a deeply nested one. Passing that data through every single component in between is called "prop drilling."&lt;/p&gt;

&lt;p&gt;Imagine you’re in a large office and you need to give a message to someone at the far end. Prop drilling is like telling the person next to you, who tells the person next to them, and so on, until the message finally arrives. It’s inefficient and annoying.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HomePage&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;HomePage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserInfo&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserInfo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;HomePage&lt;/code&gt; and &lt;code&gt;Header&lt;/code&gt; don't need the &lt;code&gt;user&lt;/code&gt; object, but they have to pass it along. That’s prop drilling.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is React Context
&lt;/h2&gt;

&lt;p&gt;React Context is the built-in solution to prop drilling. It creates a central place to store data that can be accessed by any component in its tree, without passing props down manually.&lt;/p&gt;

&lt;p&gt;Think of Context as a public announcement system in that same office. You make an announcement, and anyone who needs to hear it can listen in directly.&lt;/p&gt;

&lt;p&gt;Here’s how you’d solve the prop drilling problem with Context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 1. Create the context&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="c1"&gt;// 2. Provide the value to the component tree&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HomePage&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 3. Consume the value directly where it's needed&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// HomePage and Header no longer need to know about the user prop!&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;HomePage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserInfo&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s clean and simple. So why would we need anything else?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Big Catch with Context Performance
&lt;/h3&gt;

&lt;p&gt;Context has one major drawback. When the value in the Context Provider changes, &lt;strong&gt;every single component that consumes that context re-renders&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is fine for data that doesn't change often, like a theme (dark/light mode) or user authentication status. But what if your context holds a large object with multiple values, and only one of them changes?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AppStateContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;cartCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;userProfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Both components use the same context&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CartIcon&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cartCount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppStateContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CartIcon re-rendered&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Cart: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cartCount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userProfile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppStateContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserProfile re-rendered&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userProfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you update &lt;code&gt;cartCount&lt;/code&gt;, both &lt;code&gt;CartIcon&lt;/code&gt; and &lt;code&gt;UserProfile&lt;/code&gt; will re-render, even though &lt;code&gt;UserProfile&lt;/code&gt; doesn't care about the cart. In a large application, this causes serious performance issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Redux and Zustand
&lt;/h2&gt;

&lt;p&gt;This performance issue is the primary problem that libraries like Redux and Zustand solve. They are specialized state management tools designed to handle complex, frequently-changing state efficiently.&lt;/p&gt;

&lt;p&gt;If Context is a public announcement system, Redux and Zustand are like targeted walkie-talkies. You can send a message to a specific person (or component) without bothering everyone else.&lt;/p&gt;

&lt;p&gt;They achieve this through &lt;strong&gt;selectors&lt;/strong&gt;. A selector lets a component subscribe to only the specific pieces of state it needs. If that specific piece of state changes, only that component re-renders.&lt;/p&gt;

&lt;p&gt;Here’s a quick example using Zustand, which is known for its simplicity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zustand&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 1. Create a "store" to hold your state&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;cartCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;userProfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;incrementCart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;cartCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cartCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Components select only the state they need&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CartIcon&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cartCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStore&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cartCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CartIcon re-rendered&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Cart: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cartCount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userProfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStore&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userProfile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserProfile re-rendered&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userProfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if you call &lt;code&gt;incrementCart()&lt;/code&gt;, only &lt;code&gt;CartIcon&lt;/code&gt; will re-render. &lt;code&gt;UserProfile&lt;/code&gt; remains untouched because its selected state (&lt;code&gt;userProfile&lt;/code&gt;) didn't change. This is a huge performance win.&lt;/p&gt;

&lt;h2&gt;
  
  
  So When Should You Use Which
&lt;/h2&gt;

&lt;p&gt;Let's make it simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use React Context when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You are solving prop drilling for &lt;strong&gt;low-frequency updates&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The state is simple (e.g., theme, user info, language).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You're building a small to medium-sized app and want to avoid adding more libraries.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Redux or Zustand when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You have a &lt;strong&gt;complex global state that changes often&lt;/strong&gt; (e.g., items in a shopping cart, the state of a multi-step form, data from a real-time connection).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance is critical&lt;/strong&gt;, and you need to prevent unnecessary re-renders.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You need powerful developer tools for debugging, like the Redux DevTools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your application is large and many different components rely on the same state.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion It's Not a Replacement
&lt;/h2&gt;

&lt;p&gt;React Context is a fantastic tool for solving prop drilling, but it is not a state management library. It’s a dependency injection mechanism.&lt;/p&gt;

&lt;p&gt;Libraries like Redux and Zustand are true state management solutions. They are built to handle the complexity and performance demands of large applications.&lt;/p&gt;

&lt;p&gt;So, the next time you start a project, don't ask "Context or Redux?". Instead, ask "What kind of state am I managing?". Start with what React gives you. If your app grows and you feel the performance pain of Context, then reach for a dedicated tool like Zustand or Redux. Choose the right tool for the job.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://muhabbat.dev/post/can-react-context-really-replace-redux-zustand/" rel="noopener noreferrer"&gt;https://muhabbat.dev/post/can-react-context-really-replace-redux-zustand/&lt;/a&gt; &lt;em&gt;on September 21, 2025.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>redux</category>
    </item>
    <item>
      <title>TypeScript Generics A Practical Guide to Reusable Code</title>
      <dc:creator>Muhabbat Ali</dc:creator>
      <pubDate>Mon, 22 Sep 2025 16:09:14 +0000</pubDate>
      <link>https://forem.com/muhabbat_dev/typescript-generics-a-practical-guide-to-reusable-code-3fid</link>
      <guid>https://forem.com/muhabbat_dev/typescript-generics-a-practical-guide-to-reusable-code-3fid</guid>
      <description>&lt;h1&gt;
  
  
  TypeScript Generics A Practical Guide to Reusable Code
&lt;/h1&gt;

&lt;p&gt;As a developer, you've probably faced this problem: you write a perfectly good function that works with numbers, but then you need the exact same logic for strings. Or arrays. So what do you do? You could copy and paste the function and change the types, but that leads to duplicate code. Or you could use the &lt;code&gt;any&lt;/code&gt; type, but that throws away all the type safety that makes TypeScript great.&lt;/p&gt;

&lt;p&gt;There’s a much better way. It’s called &lt;strong&gt;generics&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Generics are a core feature of TypeScript that lets you write functions, classes, and interfaces that are flexible and reusable, all without sacrificing type safety. This guide explains what generics are, why they are so useful, and how you can start using them with practical examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Are Generics So Useful?
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, it’s important to understand &lt;em&gt;why&lt;/em&gt; generics are worth learning. They offer three huge benefits.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Write Reusable Code
&lt;/h3&gt;

&lt;p&gt;The most immediate benefit is code reuse. Instead of writing a separate function for every data type, you can write one generic function that works for all of them. This means less code to write, less code to test, and less code to maintain.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Enforce Type Safety
&lt;/h3&gt;

&lt;p&gt;Generics provide the flexibility of the &lt;code&gt;any&lt;/code&gt; type without the risk. When you use &lt;code&gt;any&lt;/code&gt;, you tell the TypeScript compiler to look the other way. With generics, you create a variable for types, so the compiler knows exactly what type you're working with at any given moment. This means you still get excellent autocompletion and error checking.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Create Flexible Components
&lt;/h3&gt;

&lt;p&gt;Generics allow you to build components that can adapt to different data types. This is incredibly powerful for creating libraries, data structures, or utility functions that need to work in a variety of situations.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Generics Work A Simple Example
&lt;/h2&gt;

&lt;p&gt;The best way to understand generics is to see them in action. Let’s create a simple function called &lt;code&gt;getFirstElement&lt;/code&gt; that takes an array and returns its first element.&lt;/p&gt;

&lt;p&gt;Without generics, we might be forced to write multiple versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFirstString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFirstNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is repetitive. Let's make it generic. We'll use a &lt;strong&gt;type variable&lt;/strong&gt;, commonly named &lt;code&gt;T&lt;/code&gt;, as a placeholder for the type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFirstElement&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break that down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; right after the function name declares &lt;code&gt;T&lt;/code&gt; as our generic type variable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;arr: T[]&lt;/code&gt; means the function accepts an array where all elements are of type &lt;code&gt;T&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;: T&lt;/code&gt; at the end means the function will return a value of type &lt;code&gt;T&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we have one function that works for any type, and it’s completely type-safe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFirstElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Type is inferred as number&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;strings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFirstElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Type is inferred as string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript is smart enough to infer the type of &lt;code&gt;T&lt;/code&gt; based on the argument we pass. We can also be explicit if we want to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstStringExplicit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFirstElement&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Useful Examples of Generics
&lt;/h2&gt;

&lt;p&gt;Generics aren’t just for simple functions. They are incredibly useful for defining more complex structures like interfaces and classes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 1 Generic Interfaces for API Responses
&lt;/h3&gt;

&lt;p&gt;When working with APIs, the shape of the response is often consistent, but the data inside changes. A generic interface is perfect for this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;APIResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APIResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APIResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abc-123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;99.99&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;APIResponse&amp;lt;T&amp;gt;&lt;/code&gt; can be reused for any type of data payload, keeping our code consistent and type-safe.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 2 Generic Classes for Data Structures
&lt;/h3&gt;

&lt;p&gt;Generics are also great for creating data structures that can hold any type of data. Let's build a simple &lt;code&gt;Stack&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stack&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numberStack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Stack&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;numberStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;numberStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numberStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 20&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stringStack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Stack&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;stringStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;stringStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stringStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "world"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;Stack&lt;/code&gt; class works seamlessly with numbers, strings, or any other type we want.&lt;/p&gt;

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

&lt;p&gt;Generics are a fundamental tool in TypeScript for writing clean, reusable, and robust code. By allowing you to create components that work over a variety of types without sacrificing type safety, they help you build more powerful and maintainable applications.&lt;/p&gt;

&lt;p&gt;If you’re not already using generics, start looking for opportunities in your code. The next time you find yourself writing duplicate logic for different types, it's the perfect time to write a generic instead.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://muhabbat.dev/post/typescript-generics-a-practical-guide-to-reusable-code" rel="noopener noreferrer"&gt;muhabbat.dev&lt;/a&gt; on September 1, 2025.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
