<?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: Krish Carter</title>
    <description>The latest articles on Forem by Krish Carter (@krish_kakadiya_5f0eaf6342).</description>
    <link>https://forem.com/krish_kakadiya_5f0eaf6342</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%2F1846530%2F40455289-6e30-40da-bd75-bc481f05482c.jpeg</url>
      <title>Forem: Krish Carter</title>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/krish_kakadiya_5f0eaf6342"/>
    <language>en</language>
    <item>
      <title>Peeking Under the Hood: How Cloudflare R2 Really Works (And Why Your Frontend Apps Will Thank You)🧑‍💻😍</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Thu, 26 Feb 2026 16:35:35 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/peeking-under-the-hood-how-cloudflare-r2-really-works-and-why-your-frontend-apps-will-thank-1nmg</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/peeking-under-the-hood-how-cloudflare-r2-really-works-and-why-your-frontend-apps-will-thank-1nmg</guid>
      <description>&lt;p&gt;You've built the perfect React app slick UI, fast interactions, maybe even some fancy image uploads for user profiles or a Next.js blog with tons of media. Everything's humming along locally... until you deploy and the storage bills hit. AWS S3 egress fees eat your budget the moment users start downloading their own avatars. Sound familiar?&lt;/p&gt;

&lt;p&gt;That's the pain Cloudflare R2 solves. No egress charges. S3-compatible API. Runs on Cloudflare's massive global network. But how does it actually pull this off without turning into a consistency nightmare or a latency slug?&lt;/p&gt;

&lt;p&gt;In this post, you'll get a clear, no-fluff tour of R2's internal architecture. We'll go from high-level concepts to the clever tricks that make it feel magical for frontend work—complete with code you can steal for your next side project. By the end, you'll know exactly when (and how) to reach for R2 instead of S3, Backblaze, or even local storage hacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Core Promise: Zero Egress, Global Scale&lt;/li&gt;
&lt;li&gt;R2's High-Level Architecture Overview&lt;/li&gt;
&lt;li&gt;Metadata Magic: Durable Objects Keep It Consistent&lt;/li&gt;
&lt;li&gt;Reading Data: Tiered Cache + Global Distribution&lt;/li&gt;
&lt;li&gt;Writing Data: Local Uploads and Background Replication&lt;/li&gt;
&lt;li&gt;Practical Example: Uploading and Serving Images from a Next.js App&lt;/li&gt;
&lt;li&gt;Advanced Tips and Gotchas for Frontend Devs&lt;/li&gt;
&lt;li&gt;Common Mistakes That Burn You&lt;/li&gt;
&lt;li&gt;Wrapping Up: Level Up Your Storage Game&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Core Promise: Zero Egress, Global Scale
&lt;/h2&gt;

&lt;p&gt;Why care about internals? Because understanding why R2 behaves the way it does helps you design better systems.&lt;/p&gt;

&lt;p&gt;Traditional object stores like S3 charge for data leaving their region. Cloudflare's edge network (330+ locations) changes the game: data is served from the nearest point-of-presence (PoP), often without ever hitting a "central" origin. No egress bill because the transfer happens on Cloudflare's backbone.&lt;br&gt;
But global-anywhere reads + strong consistency sounds impossible. R2 achieves it by decoupling metadata from payload storage and leaning hard on Cloudflare primitives.&lt;/p&gt;

&lt;p&gt;Always think "&lt;strong&gt;edge-first.&lt;/strong&gt;" If your app serves public assets (images, videos, user uploads), R2 + Cloudflare Images/Stream can slash costs and latency compared to centralized providers.&lt;/p&gt;
&lt;h2&gt;
  
  
  R2's High-Level Architecture Overview
&lt;/h2&gt;

&lt;p&gt;R2 breaks into four key layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;R2 Gateway&lt;/strong&gt; — Edge Workers handling auth, routing, S3 API translation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata Service&lt;/strong&gt; — Distributed Durable Objects for object keys, checksums, versions—ensuring strong consistency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tiered Read Cache&lt;/strong&gt; — Multi-level caching leveraging Cloudflare's Tiered Cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed Storage Infrastructure&lt;/strong&gt; — Encrypted, erasure-coded persistent storage across regions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Requests hit the nearest edge → gateway routes → metadata checked → data pulled from cache or backing store.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftkn5bjhahsb2h58gunsf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftkn5bjhahsb2h58gunsf.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Metadata Magic: Durable Objects Keep It Consistent
&lt;/h2&gt;

&lt;p&gt;Durable Objects are single-instance, stateful Workers. R2 uses them for metadata: each object key maps to a Durable Object that holds info like ETag, size, last-modified.&lt;/p&gt;

&lt;p&gt;When you PUT an object:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gateway routes to the DO responsible for that key.&lt;/li&gt;
&lt;li&gt;DO updates metadata atomically.&lt;/li&gt;
&lt;li&gt;Payload goes to storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reads hit the DO first → fast metadata cache → then data fetch.&lt;/p&gt;

&lt;p&gt;This avoids distributed locks or consensus hell. Durable Objects provide coordination without traditional databases.&lt;/p&gt;

&lt;p&gt;For **custom **needs, bind R2 buckets directly in Workers for zero-latency metadata ops.&lt;/p&gt;

&lt;p&gt;Tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// In a Cloudflare Worker
export default {
  async fetch(request, env) {
    const object = await env.MY_BUCKET.get('profile-pic.jpg');
    if (object === null) return new Response('Not found', { status: 404 });

    const data = await object.arrayBuffer();
    return new Response(data, {
      headers: { 'Content-Type': 'image/jpeg' },
    });
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reading Data: Tiered Cache + Global Distribution
&lt;/h2&gt;

&lt;p&gt;Reads shine here. Cloudflare Tiered Cache sits in front:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;L1: PoP-level cache (super fast if hit).&lt;/li&gt;
&lt;li&gt;L2: Regional.&lt;/li&gt;
&lt;li&gt;Miss → Distributed Storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because data is replicated/erasure-coded across locations, hot objects get cached globally.&lt;/p&gt;

&lt;p&gt;No egress: delivery is from edge cache → client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility Note&lt;/strong&gt;&lt;br&gt;
When serving images, always add &lt;code&gt;alt&lt;/code&gt;text and consider &lt;code&gt;loading="lazy"&lt;/code&gt; + responsive &lt;code&gt;srcset&lt;/code&gt;. R2 pairs perfectly with &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt; components in Next.js.&lt;/p&gt;
&lt;h2&gt;
  
  
  Writing Data: Local Uploads and Background Replication
&lt;/h2&gt;

&lt;p&gt;New in 2026: &lt;strong&gt;Local Uploads&lt;/strong&gt; (beta). Enable it → client uploads to nearest PoP storage.&lt;/p&gt;

&lt;p&gt;Metadata publishes immediately to bucket's "home" region DO. Background job replicates payload asynchronously with retries.&lt;br&gt;
Result: ~75% lower write latency for global users no waiting for cross-region sync.&lt;/p&gt;

&lt;p&gt;Without Local Uploads, writes route to bucket's location hint (or auto).&lt;/p&gt;
&lt;h2&gt;
  
  
  Practical Example: Uploading and Serving Images from a Next.js App
&lt;/h2&gt;

&lt;p&gt;Let's build a simple user avatar uploader.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create R2 bucket in dashboard.&lt;/li&gt;
&lt;li&gt;Generate S3-compatible credentials (Access Key ID, Secret).&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;@aws-sdk/client-s3&lt;/code&gt; with custom endpoint.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// lib/r2.ts
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

const r2 = new S3Client({
  region: 'auto',
  endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
  credentials: {
    accessKeyId: process.env.R2_ACCESS_KEY_ID!,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
  },
});

export async function uploadAvatar(file: File, userId: string) {
  const key = `avatars/${userId}.jpg`;
  await r2.send(new PutObjectCommand({
    Bucket: 'my-app-bucket',
    Key: key,
    Body: Buffer.from(await file.arrayBuffer()),
    ContentType: file.type,
  }));
  return `https://pub-&amp;lt;your-pub-hash&amp;gt;.r2.dev/${key}`;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your component:&lt;/p&gt;

&lt;p&gt;Tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// app/upload/page.tsx
'use client';

import { uploadAvatar } from '@/lib/r2';

export default function Upload() {
  const handleUpload = async (e: React.ChangeEvent&amp;lt;HTMLInputElement&amp;gt;) =&amp;gt; {
    const file = e.target.files?.[0];
    if (!file) return;
    const url = await uploadAvatar(file, 'krish123');
    console.log('Avatar URL:', url);
  };

  return &amp;lt;input type="file" onChange={handleUpload} /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Common Mistakes That Burn You&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forgetting region=&lt;code&gt;auto&lt;/code&gt;in SDK → weird errors.&lt;/li&gt;
&lt;li&gt;Assuming eventual consistency → test read-after-write.&lt;/li&gt;
&lt;li&gt;Public bucket without CORS → browser blocks fetches.&lt;/li&gt;
&lt;li&gt;Ignoring Class B ops costs → listObjectsV2 can add up on large buckets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Wrapping Up: Level Up Your Storage Game&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;R2 isn't just "cheap S3." Its edge-native design, Durable Objects metadata, tiered caching, and new Local Uploads make it a frontend superpower: fast, predictable costs, global performance without ops overhead.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>cloudflarechallenge</category>
      <category>learning</category>
    </item>
    <item>
      <title>Why Your React App Feels Slow (Even When It Looks Fine) And How React Doctor Fixes It in Seconds 🧑‍💻⌨️</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Tue, 24 Feb 2026 15:04:23 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/why-your-react-app-feels-slow-even-when-it-looks-fine-and-how-react-doctor-fixes-it-in-seconds-3l74</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/why-your-react-app-feels-slow-even-when-it-looks-fine-and-how-react-doctor-fixes-it-in-seconds-3l74</guid>
      <description>&lt;p&gt;You've been there: your React app feels sluggish, re-renders are happening more than you'd like, and debugging sessions stretch into the night. You profile with React DevTools, chase down memoization misses, and still wonder — "Why is this component re-rendering on every keystroke?"&lt;/p&gt;

&lt;p&gt;The culprit is often not one big mistake, but dozens of small anti-patterns that accumulate over time. Unnecessary useEffect hooks computing derived state. Prop drilling through five levels instead of composition. Missing key props that silently break list reconciliation. Accessibility oversights that hurt real users.&lt;/p&gt;

&lt;p&gt;These issues don't scream during development they whisper performance regressions, bugs during refactors, and frustrated users. In large codebases, they compound until your app feels "heavy" for no obvious reason.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;React Doctor&lt;/strong&gt;&lt;br&gt;
 A free, open-source CLI tool that acts like a code physician. Run one command, and it scans your entire React project (Next.js, Vite, Remix, whatever), detects framework setup, React version, and compiler config, then flags issues with file-by-file precision. It outputs a 0-100 health score and prioritizes fixes that deliver the biggest wins.&lt;/p&gt;

&lt;p&gt;In this post, you'll learn exactly how to use React Doctor, why its warnings matter, and how to fix the most common issues it surfaces. By the end, you'll have a repeatable workflow to keep your React code lean, accessible, and maintainable.&lt;/p&gt;
&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What React Doctor Actually Does&lt;/li&gt;
&lt;li&gt;Getting Started: One Command to Rule Them All&lt;/li&gt;
&lt;li&gt;The Most Common Warnings (And Why They Hurt)&lt;/li&gt;
&lt;li&gt;Fixing Unnecessary useEffect: The Silent Performance Killer&lt;/li&gt;
&lt;li&gt;Beyond Hooks: Accessibility, Keys, and Architecture Smells&lt;/li&gt;
&lt;li&gt;Advanced: Integrating React Doctor into Your Workflow&lt;/li&gt;
&lt;li&gt;Common Gotchas When Interpreting Results&lt;/li&gt;
&lt;li&gt;Wrapping Up: Make Code Health a Habi&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What React Doctor Actually Does
&lt;/h2&gt;

&lt;p&gt;React Doctor isn't a runtime profiler like React Scan — it's a &lt;strong&gt;static analyzer&lt;/strong&gt; powered by fast Rust based tooling (Oxlint under the hood). It parses your code without running it, applies rules tuned for modern React (hooks, Server Components, server actions), and catches patterns that lead to bugs or slowness.&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting Started: One Command to Rule Them All
&lt;/h2&gt;

&lt;p&gt;Installation? None. Just npx it:&lt;/p&gt;

&lt;p&gt;Bash&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx -y react-doctor@latest .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.&lt;/code&gt; tells it to scan the current directory. In seconds (yes, even on big monorepos), you'll see output like:&lt;/p&gt;

&lt;p&gt;Text&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React Doctor vX.Y.Z
Scanning project...
Framework: Next.js 15
React: 19.0.0-rc
Compiler: Turbopack

Health Score: 82/100

Critical (1):
- src/app/actions/deleteUser.ts:18 Missing authentication check in server action

Warnings (42):
- src/components/UserProfile.tsx:45 Derived state in useEffect — compute in render
- src/features/TodoList.tsx:22 Using index as key in mapped list
...

Accessibility (8):
- src/components/AnimatedModal.tsx:67 Missing prefers-reduced-motion check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gotcha!&lt;/strong&gt;&lt;br&gt;
If you're in a monorepo, cd into the app folder first or use &lt;code&gt;--dir ./apps/web&lt;/code&gt; (check docs for flags).&lt;br&gt;
&lt;strong&gt;Accessibility Note&lt;/strong&gt;&lt;br&gt;
Many warnings highlight a11y gaps, like missing reduced-motion handling that improve UX for users with vestibular disorders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Most Common Warnings (And Why They Hurt)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React Doctor surfaces patterns you've probably written without thinking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Derived state in useEffect&lt;/strong&gt;— recomputes on every render cycle instead of during render.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uncleaned async in effects&lt;/strong&gt; → race conditions on unmount.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index as key&lt;/strong&gt; → broken animations/reordering in lists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prop drilling&lt;/strong&gt; → brittle components, hard refactors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server action security&lt;/strong&gt; → missing auth checks → vulnerability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No reduced-motion&lt;/strong&gt;→ jarring experiences for sensitive users.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Fixing Unnecessary useEffect: The Silent Performance Kille
&lt;/h2&gt;

&lt;p&gt;This is the #1 warning in most codebases. Classic anti-pattern:&lt;/p&gt;

&lt;p&gt;tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function ExpensiveList({ items }) {
  const [sortedItems, setSortedItems] = useState([]);

  useEffect(() =&amp;gt; {
    setSortedItems([...items].sort((a, b) =&amp;gt; a.name.localeCompare(b.name)));
  }, [items]);

  return &amp;lt;ul&amp;gt;{sortedItems.map(item =&amp;gt; &amp;lt;li key={item.id}&amp;gt;{item.name}&amp;lt;/li&amp;gt;)}&amp;lt;/ul&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why it's bad: Every time &lt;code&gt;items&lt;/code&gt; changes → effect runs → state update → re-render → potential loop if parent re-renders often.&lt;/p&gt;

&lt;p&gt;Fix —** compute during render:**&lt;/p&gt;

&lt;p&gt;tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function ExpensiveList({ items }) {
  const sortedItems = useMemo(() =&amp;gt; {
    return [...items].sort((a, b) =&amp;gt; a.name.localeCompare(b.name));
  }, [items]);

  return &amp;lt;ul&amp;gt;{sortedItems.map(item =&amp;gt; &amp;lt;li key={item.id}&amp;gt;{item.name}&amp;lt;/li&amp;gt;)}&amp;lt;/ul&amp;gt;;
}```



**Tip**
`useMemo `is your friend here, but don't overuse it, only when the sort is expensive. React Doctor helps you spot when you need it.

## Beyond Hooks: Accessibility, Keys, and Architecture Smells

For keys in lists:
Bad:


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

&lt;/div&gt;

&lt;p&gt;{items.map((item, index) =&amp;gt; )}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Good:



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

&lt;/div&gt;

&lt;p&gt;{items.map(item =&amp;gt; )}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

React Doctor flags index-as-key because reordering items causes unnecessary DOM mutations and lost state.

For accessibility animations without reduced-motion checks:

tsx


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

&lt;/div&gt;

&lt;p&gt;// Add this wrapper&lt;br&gt;
const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');&lt;/p&gt;

&lt;p&gt;if (prefersReducedMotion) {&lt;br&gt;
  // no animation&lt;br&gt;
} else {&lt;br&gt;
  // animate&lt;br&gt;
}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

**Wrapping Up: Make Code Health a Habit**

Mastering tools like React Doctor shifts you from reactive firefighting to proactive quality. Your apps become faster, more accessible, and easier to maintain especially as teams grow.

Next steps:

Run `npx react-doctor@latest .` on your current project today.
Tackle the top 5 warnings.
Add it to CI for ongoing health checks.

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

&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>resources</category>
      <category>learning</category>
    </item>
    <item>
      <title>Peeking Under the Hood: How Supabase Storage Really Works (And Why It Feels Like Magic)</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Wed, 18 Feb 2026 13:15:59 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/peeking-under-the-hood-how-supabase-storage-really-works-and-why-it-feels-like-magic-2i69</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/peeking-under-the-hood-how-supabase-storage-really-works-and-why-it-feels-like-magic-2i69</guid>
      <description>&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Big Picture: Storage as Postgres + Object Store Hybrid&lt;/li&gt;
&lt;li&gt;Buckets, Objects, and the Metadata Layer&lt;/li&gt;
&lt;li&gt;Uploads: From TUS Resumable to S3-Compatible Magic&lt;/li&gt;
&lt;li&gt;Security Deep Dive: Row-Level Security Meets File Access&lt;/li&gt;
&lt;li&gt;Serving Files: Signed URLs, Public Buckets, and Edge Delivery&lt;/li&gt;
&lt;li&gt;Advanced Patterns: Image Transformations and Integrations&lt;/li&gt;
&lt;li&gt;Common Pitfalls and Pro Tips&lt;/li&gt;
&lt;li&gt;Wrapping Up: Level Up Your File Handling&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Big Picture: Storage as Postgres + Object Store Hybrid
&lt;/h2&gt;

&lt;p&gt;Supabase Storage isn't just another blob store it's a clever marriage of PostgreSQL for metadata and access control, and an S3-compatible object store (primarily Amazon S3 under the hood, with support for others) for the actual heavy lifting of file bytes.&lt;/p&gt;

&lt;p&gt;Why this hybrid?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Postgres gives you battle-tested relational power: fine-grained Row Level Security (RLS), transactions, and queries.&lt;/li&gt;
&lt;li&gt;S3 gives you infinite scale, durability, and cheap storage for raw bytes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result? You get file permissions as expressive as your database policies, while the heavy files live where they belong on object storage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip:-&lt;/strong&gt;&lt;br&gt;
Think of Storage as "Postgres wearing an S3 hat." Every file operation starts in Postgres (auth, policy check), then proxies to S3.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Note:-&lt;/strong&gt;&lt;br&gt;
Don't assume Storage is purely serverless like Firebase—it's backed by real Postgres instances, so heavy metadata operations (listing thousands of files) can hit query limits if you're not careful.&lt;/p&gt;
&lt;h2&gt;
  
  
  Buckets, Objects, and the Metadata Layer
&lt;/h2&gt;

&lt;p&gt;Everything starts with &lt;strong&gt;buckets&lt;/strong&gt;. You create them in the dashboard or via API:&lt;/p&gt;

&lt;p&gt;Javascript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { data, error } = await supabase.storage.createBucket('avatars', {
  public: false,
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buckets are rows in a Postgres table (&lt;code&gt;storage.buckets&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Each bucket has config like &lt;code&gt;public&lt;/code&gt;, &lt;code&gt;allowed_mime_types&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Files (objects) live in another table (&lt;code&gt;storage.objects&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;bucket_id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;(path), &lt;code&gt;metadata&lt;/code&gt;(JSONB), &lt;code&gt;owner&lt;/code&gt;(user UUID), etc.&lt;/li&gt;
&lt;li&gt;The actual file path in S3 is something like &lt;code&gt;bucket-name/user-id/random-uuid.ext&lt;/code&gt;, but you never see that—Supabase abstracts it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This metadata layer lets you query files relationally:&lt;/p&gt;

&lt;p&gt;SQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Example: Find all avatars owned by a user
SELECT * FROM storage.objects
WHERE bucket_id = 'avatars'
AND owner = 'uuid-of-user';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;&lt;br&gt;
Use &lt;code&gt;metadata&lt;/code&gt;JSONB for custom tags (e.g., &lt;code&gt;{ "project_id": 123 }&lt;/code&gt;)—query them efficiently with GIN indexes if needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility Note&lt;/strong&gt;&lt;br&gt;
When storing images, always add alt text metadata and enforce it in your frontend forms—Supabase won't do it for you.&lt;/p&gt;
&lt;h2&gt;
  
  
  Uploads: From TUS Resumable to S3-Compatible Magic
&lt;/h2&gt;

&lt;p&gt;Tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// React example with progress
const uploadFile = async (file: File) =&amp;gt; {
  const { data, error } = await supabase.storage
    .from('avatars')
    .upload(`public/${user.id}/${file.name}`, file, {
      upsert: true,
      contentType: file.type,
    });

  if (error) console.error(error);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client → Supabase Storage API (Node.js/Fastify service).&lt;/li&gt;
&lt;li&gt;API checks auth + RLS policy for insert on storage.objects.&lt;/li&gt;
&lt;li&gt;For large files, Supabase uses TUS protocol (resumable uploads) via libraries like Uppy.&lt;/li&gt;
&lt;li&gt;Chunked data streams directly to S3 (multipart upload).&lt;/li&gt;
&lt;li&gt;Once complete, metadata row is committed in Postgres transactionally.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since late 2024/early 2025, Supabase Storage is fully S3 compatible can use AWS SDKs directly:&lt;/p&gt;

&lt;p&gt;Javascript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Using AWS SDK v3 with Supabase credentials
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

const s3 = new S3Client({
  region: 'auto', // Supabase uses 'auto'
  endpoint: 'https://&amp;lt;project-ref&amp;gt;.supabase.co/storage/v1/s3',
  credentials: {
    accessKeyId: 'your-supabase-access-key',
    secretAccessKey: 'your-supabase-secret-key',
  },
  forcePathStyle: true,
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security Deep Dive: Row-Level Security Meets File Access
&lt;/h2&gt;

&lt;p&gt;This is where Supabase shines.&lt;br&gt;
Policies live on &lt;code&gt;storage.objects&lt;/code&gt; table, just like database tables.&lt;/p&gt;

&lt;p&gt;Example policy: Users can only upload to their own folder:&lt;/p&gt;

&lt;p&gt;SQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE POLICY "Users can upload own avatars"
ON storage.objects FOR INSERT
TO authenticated
WITH CHECK (
  bucket_id = 'avatars'
  AND (storage.foldername(name))[1] = auth.uid()::text
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;storage.foldername(name)&lt;/code&gt; extracts path segments.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;auth.uid()&lt;/code&gt; pulls the JWT user ID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Combine with public buckets for CDNs—public buckets bypass auth but still respect allowed_mime_types.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Serving Files: Signed URLs, Public Buckets, and Edge Delivery
&lt;/h2&gt;

&lt;p&gt;Public bucket file: &lt;code&gt;https://&amp;lt;project-ref&amp;gt;.supabase.co/storage/v1/object/public/avatars/user123/photo.jpg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Private: Use signed URLs (time-limited):&lt;br&gt;
Javascript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { data } = await supabase.storage
  .from('private-docs')
  .createSignedUrl('reports/q4.pdf', 60); // 60 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internally, signed URLs are JWTs verified by the Storage API, which proxies to S3 with presigned URLs.&lt;br&gt;
Edge caching? Supabase leverages CDN providers for public assets-low-latency global delivery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advanced Patterns: Image Transformations and Integrations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Supabase Storage supports on-the-fly image transforms (via imgproxy integration):&lt;/p&gt;

&lt;p&gt;Javascript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Resize to 200x200
const { data } = supabase.storage
  .from('avatars')
  .getPublicUrl('user123/photo.jpg', {
    transform: { width: 200, height: 200, resize: 'cover' }
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood: Requests hit an edge worker that pulls from S3, transforms, caches.&lt;br&gt;
Pair with Edge Functions for custom processing (watermarking, virus scanning).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cache transformed images aggressively use &lt;code&gt;Cache-Control&lt;/code&gt; headers in metadata.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Pitfalls and Pro Tips
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Listing huge buckets → Use pagination + search params.&lt;br&gt;
&lt;strong&gt;Pitfall:&lt;/strong&gt; Signed URLs expiring mid-session → Refresh on demand.&lt;br&gt;
&lt;strong&gt;Pro Tip:&lt;/strong&gt; Monitor usage via &lt;code&gt;pg_stat_statements&lt;/code&gt; for metadata bottlenecks.&lt;br&gt;
&lt;strong&gt;Pro Tip:&lt;/strong&gt; For ultra-scale, consider direct S3 uploads with presigned URLs generated from Edge Functions.&lt;/p&gt;

</description>
      <category>supabse</category>
      <category>webdev</category>
      <category>learning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Inside Supabase Edge Functions: How Serverless Magic Actually Works</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Tue, 17 Feb 2026 13:20:47 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/inside-supabase-edge-functions-how-serverless-magic-actually-works-2m1p</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/inside-supabase-edge-functions-how-serverless-magic-actually-works-2m1p</guid>
      <description>&lt;p&gt;Discover the inner mechanics of Supabase's globally distributed serverless functions and how they power low-latency apps with Deno at their core.&lt;/p&gt;

&lt;p&gt;Hey there! If you've ever built a web app and hit that frustrating wall where your server-side logic feels sluggish or overly complicated, you're not alone. Supabase Edge Functions are a game-changer for handling things like webhooks, API integrations, or even generating dynamic content right at the edge of the network closer to your users for that snappy performance.&lt;/p&gt;

&lt;p&gt;In this guide, we'll peel back the layers of how these functions actually work underneath. You'll learn the architecture, runtime details, and deployment flow, all while building up from basics to advanced tweaks. By the end, you'll be equipped to integrate them into your own projects, solving real problems like reducing latency in global apps or securely orchestrating third-party services. Let's dive in it's going to be fun and practical.&lt;/p&gt;

&lt;p&gt;Table of Contents&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Basics: What Are Supabase Edge Functions?&lt;/li&gt;
&lt;li&gt;A Practical Example: Building Your First Function&lt;/li&gt;
&lt;li&gt;Visual Intuition: Mapping the Architecture&lt;/li&gt;
&lt;li&gt;Real-World Use Case: Handling a Stripe Webhook&lt;/li&gt;
&lt;li&gt;Advanced Tips: Optimizing for Scale and Security&lt;/li&gt;
&lt;li&gt;Wrapping It Up: Why This Matters for Your Apps&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Basics: What Are Supabase Edge Functions?
&lt;/h2&gt;

&lt;p&gt;Let's start simple. At their core, Supabase Edge Functions are &lt;strong&gt;TypeScript-based&lt;/strong&gt; serverless functions that run on a globally distributed network. Think of them as lightweight scripts that execute server side logic without you managing servers perfect for tasks that need to happen quickly, like processing payments or fetching data from APIs.&lt;/p&gt;

&lt;p&gt;Why does this matter? Traditional serverless setups often run in a single region, leading to higher latency for users far away. Edge Functions flip that by deploying your code to edge nodes worldwide, so requests get handled closer to the source. Underneath, they're powered by Deno, a secure runtime that's TypeScript-native and supports things like WebAssembly (WASM) for extra flexibility.&lt;/p&gt;

&lt;p&gt;You'll write these as single file handlers. Here's a bare-bones example to get the idea:&lt;/p&gt;

&lt;p&gt;Typescript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deno.serve(async (req) =&amp;gt; {
  return new Response("Hello from the edge!");
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exports a handler that responds to incoming requests. Deno takes care of the rest, making it feel more like writing client-side code but with server powers.&lt;/p&gt;

&lt;p&gt;Tip: for Beginners&lt;br&gt;
Deno isn't Node.js don't try importing Node modules directly. Stick to Deno compatible libraries, and remember that environment variables are accessed via &lt;code&gt;Deno.env.get('KEY')&lt;/code&gt;. This keeps things secure and avoids common compatibility headaches.&lt;/p&gt;
&lt;h2&gt;
  
  
  A Practical Example: Building Your First Function
&lt;/h2&gt;

&lt;p&gt;Now that you've got the basics, let's put it into action. Suppose you want a function that echoes back whatever JSON you send it great for testing or simple APIs.&lt;/p&gt;

&lt;p&gt;First, you'll use the Supabase CLI to set up locally. Install it if you haven't (&lt;code&gt;npm install -g supabase&lt;/code&gt;), then run &lt;code&gt;supabase init&lt;/code&gt; in your project folder. Create a new function with &lt;code&gt;supabase functions new echo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;echo/index.ts&lt;/code&gt; file, drop this in:&lt;/p&gt;

&lt;p&gt;Typescript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deno.serve(async (req) =&amp;gt; {
  if (req.method === 'POST') {
    const body = await req.json();
    return new Response(JSON.stringify({ echoed: body }), {
      headers: { 'Content-Type': 'application/json' },
      status: 200,
    });
  }
  return new Response('Only POST allowed', { status: 405 });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test locally: &lt;strong&gt;&lt;code&gt;supabase functions serve echo&lt;/code&gt;&lt;/strong&gt;. Hit it with a tool like curl: &lt;code&gt;curl -X POST http://localhost:54321/functions/v1/echo&lt;/code&gt; &lt;code&gt;-H "Content-Type: application/json" -d '{"message": "Hello!"}'.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You'll see the response instantly. Deploy it globally with &lt;code&gt;supabase functions deploy echo&lt;/code&gt;, and boom it's live on the edge network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Gotcha for Beginners&lt;br&gt;
Local serving mimics production, but watch for environment variables. Set them in your &lt;strong&gt;.env&lt;/strong&gt; file and load with &lt;strong&gt;supabase secrets set&lt;/strong&gt;, or you'll chase "undefined" errors when deploying.&lt;/p&gt;
&lt;h2&gt;
  
  
  Visual Intuition: Mapping the Architecture
&lt;/h2&gt;

&lt;p&gt;Explanations are great, but visuals make things click. Imagine a flow where a user's request hits an edge gateway first think of it as a smart bouncer that checks auth, applies rules, and routes to the nearest runtime node.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Tip :&lt;/strong&gt; Gotcha for Beginners&lt;br&gt;
Don't assume the gateway handles everything automatically. You still need to verify auth in your code if sensitivity demands it, or risk exposing data on public endpoints.&lt;/p&gt;
&lt;h2&gt;
  
  
  Real-World Use Case: Handling a Stripe Webhook
&lt;/h2&gt;

&lt;p&gt;Let's level up to something you'd actually ship. Say you're building an e-commerce app and need to process Stripe payments securely. Edge Functions shine here because webhooks require low-latency responses to avoid timeouts.&lt;/p&gt;

&lt;p&gt;You'll create a function that listens for Stripe's &lt;strong&gt;checkout.session.completed&lt;/strong&gt; event, then updates your Supabase database.&lt;/p&gt;

&lt;p&gt;First, import the Supabase client:&lt;/p&gt;

&lt;p&gt;Typescript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createClient } from '@supabase/supabase-js';
import Stripe from 'https://esm.sh/stripe@8.174.0?deno-std=0.63.0';

const supabase = createClient(
  Deno.env.get('SUPABASE_URL')!,
  Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
);

const stripe = Stripe(Deno.env.get('STRIPE_SECRET_KEY')!);

Deno.serve(async (req) =&amp;gt; {
  if (req.method === 'POST') {
    const signature = req.headers.get('stripe-signature');
    let event;
    try {
      const body = await req.text();
      event = stripe.webhooks.constructEvent(
        body,
        signature!,
        Deno.env.get('STRIPE_WEBHOOK_SECRET')!
      );
    } catch (err) {
      return new Response(`Webhook Error: ${err.message}`, { status: 400 });
    }

    if (event.type === 'checkout.session.completed') {
      const session = event.data.object;
      // Update database
      const { error } = await supabase
        .from('orders')
        .update({ status: 'paid' })
        .eq('id', session.metadata.order_id);

      if (error) return new Response('DB Error', { status: 500 });
    }

    return new Response('Success', { status: 200 });
  }
  return new Response('Method Not Allowed', { status: 405 });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy this, configure your Stripe webhook to point to the function URL, and you're set. This handles real payments with edge speed.&lt;/p&gt;

&lt;p&gt;Why this works underneath: The gateway routes the request efficiently, Deno runs it securely, and Supabase integrations keep data in sync.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Gotcha for Beginners&lt;br&gt;
Webhooks can replay events make your handlers idempotent (e.g., check if the order is already paid) to avoid duplicate updates.&lt;/p&gt;
&lt;h2&gt;
  
  
  Advanced Tips: Optimizing for Scale and Security
&lt;/h2&gt;

&lt;p&gt;You've got the foundations now let's tweak for production. Edge Functions integrate deeply with Supabase's ecosystem, like using the service role key for admin access to Postgres or Storage.&lt;/p&gt;

&lt;p&gt;For secrets: Store API keys via &lt;code&gt;supabase secrets set STRIPE_KEY=sk_test_...&lt;/code&gt; and access with &lt;code&gt;Deno.env.get()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scaling tip:&lt;/strong&gt; Avoid long-running tasks, offload to background workers. For concurrency, design functions to be stateless.&lt;/p&gt;

&lt;p&gt;Advanced example: Generating OG images on-the-fly from Storage:&lt;/p&gt;

&lt;p&gt;Typescript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createClient } from '@supabase/supabase-js';

const supabase = createClient(
  Deno.env.get('SUPABASE_URL')!,
  Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
);

Deno.serve(async (req) =&amp;gt; {
  const { data, error } = await supabase.storage
    .from('images')
    .download('template.png');

  if (error) return new Response('Error', { status: 500 });

  // Imagine processing with a library like Sharp (Deno-compatible)
  // For simplicity, return the raw image
  return new Response(data, {
    headers: { 'Content-Type': 'image/png' },
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pulls from Storage and serves dynamicallygreat for social previews.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security tip:&lt;/strong&gt; Always validate JWTs manually if needed, even with gateway help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping It Up: Why This Matters for Your Apps
&lt;/h2&gt;

&lt;p&gt;We've covered a lot: From the Deno powered basics and simple setups to architectural flows, real Stripe integrations, optimization tricks, and pitfalls to dodge. At its heart, Supabase Edge Functions let you build scalable, low-latency backends without the infrastructure hassle empowering you to focus on features that delight users.&lt;/p&gt;

&lt;p&gt;Next, experiment with your own function. Deploy something small, like a weather API wrapper, and see the speed difference. If you're hooked, explore deeper integrations or even self-hosting the runtime.&lt;br&gt;
Feel free to tweak these examples and share what you build I'd love to hear how it goes!&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>beginners</category>
      <category>learning</category>
      <category>webdev</category>
    </item>
    <item>
      <title>An Interactive Guide to Firebase Cloud Messaging⌨️🧑‍💻</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Mon, 16 Feb 2026 14:30:30 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/an-interactive-guide-to-firebase-cloud-messaging-4oe0</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/an-interactive-guide-to-firebase-cloud-messaging-4oe0</guid>
      <description>&lt;p&gt;Unlock the power of real-time push notifications and discover how FCM keeps your users engaged without draining your resources.&lt;/p&gt;

&lt;p&gt;Hey there! If you've ever built a mobile or web app that needs to ping users with updates like a new message in a chat app or a breaking news alert you know how tricky notifications can be. They're essential for keeping users coming back, but handling them across platforms? That's where things get messy. Enter Firebase Cloud Messaging (FCM), Google's free, cross-platform service that makes sending notifications feel almost effortless.&lt;/p&gt;

&lt;p&gt;In this guide, we'll dive deep into how FCM actually works under the hood. You'll learn the core concepts, walk through a practical setup, visualize the flow with diagrams, and even tackle advanced tricks. By the end, you'll be equipped to add reliable push notifications to your own projects, solving that nagging problem of user retention in a world full of distractions. Let's get started, I'll explain everything step by step, just like we're chatting over coffee.&lt;/p&gt;

&lt;p&gt;Table of Contents&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is Firebase Cloud Messaging?&lt;/li&gt;
&lt;li&gt;Setting Up FCM in Your App&lt;/li&gt;
&lt;li&gt;Visualizing the Message Flow&lt;/li&gt;
&lt;li&gt;A Real-World Use Case: Chat App Notifications&lt;/li&gt;
&lt;li&gt;Advanced Tips for FCM&lt;/li&gt;
&lt;li&gt;Common Mistakes and How to Avoid Them&lt;/li&gt;
&lt;li&gt;Wrapping It Up&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Firebase Cloud Messaging?
&lt;/h2&gt;

&lt;p&gt;Let's start at the beginning. Firebase Cloud Messaging, or FCM, is essentially a messaging service from Google that lets you send notifications or data payloads to devices running your app. It's cross-platform, so whether your users are on Android, iOS, or even a web browser, FCM handles the delivery for you—at no cost.&lt;/p&gt;

&lt;p&gt;Why does this matter? In real projects, notifications aren't just bells and whistles; they're the glue that keeps users engaged. Think about how apps like Twitter or WhatsApp pull you back in with timely alerts. FCM abstracts away the platform-specific headaches, like dealing with Apple's APNs or Android's Google Play Services, so you can focus on what your app does best.&lt;/p&gt;

&lt;p&gt;At its core, FCM works by routing messages from your server (or a trusted environment like Cloud Functions) through Google's backend to the target devices. There are two main types of messages: notification messages, which the system automatically displays to the user, and data messages, which your app handles silently for custom logic.&lt;br&gt;
Here's a quick example of what a basic notification message looks like in JSON format, as you'd send it from your server:&lt;/p&gt;

&lt;p&gt;JSON&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "message": {
    "token": "DEVICE_TOKEN_HERE",
    "notification": {
      "title": "Hello from FCM!",
      "body": "This is your first push notification."
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This payload gets sent via the FCM API, and poof the user's device shows a notification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; A common gotcha for beginners is confusing notification vs. data messages. If you send a notification message but want custom handling (like updating a chat UI without showing a banner), switch to data messages instead. It'll give you full control in your app's code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up FCM in Your App
&lt;/h2&gt;

&lt;p&gt;Now that you know what FCM is, let's get hands-on. We'll focus on integrating it into a web app, since that's a common starting point for many developers (and it plays nicely with JavaScript frameworks like React). The process is similar for mobile, but we'll keep it web-focused here for brevity.&lt;/p&gt;

&lt;p&gt;First, why set this up? In a real project, this enables features like real-time updates without constant polling, saving battery and data. You'll need a Firebase project—head to the Firebase console, create one if you haven't, and grab your config object.&lt;/p&gt;

&lt;p&gt;Start by including the Firebase SDK in your web app. Add this to your &lt;code&gt;index.html&lt;/code&gt;:&lt;br&gt;
HTML&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script src="https://www.gstatic.com/firebasejs/10.7.1/firebase-app.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src="https://www.gstatic.com/firebasejs/10.7.1/firebase-messaging.js"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, initialize Firebase and request the registration token (a unique ID for the device):&lt;/p&gt;

&lt;p&gt;JavaScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { initializeApp } from 'firebase/app';
import { getMessaging, getToken, onMessage } from 'firebase/messaging';

const firebaseConfig = {
  // Your config from Firebase console
  apiKey: "YOUR_API_KEY",
  authDomain: "your-project.firebaseapp.com",
  projectId: "your-project",
  storageBucket: "your-project.appspot.com",
  messagingSenderId: "YOUR_SENDER_ID",
  appId: "YOUR_APP_ID",
  measurementId: "YOUR_MEASUREMENT_ID"
};

const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);

// Request permission and get token
Notification.requestPermission().then(permission =&amp;gt; {
  if (permission === 'granted') {
    getToken(messaging, { vapidKey: 'YOUR_VAPID_KEY' }).then(token =&amp;gt; {
      console.log('Registration token:', token);
      // Send this token to your server to store it
    }).catch(err =&amp;gt; console.error('Error getting token:', err));
  }
});

// Handle incoming messages in the foreground
onMessage(messaging, payload =&amp;gt; {
  console.log('Message received:', payload);
  // Display a custom notification or update UI
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll also need a service worker for background messages. Create a &lt;code&gt;firebase-messaging-sw.js&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;JavaScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;importScripts('https://www.gstatic.com/firebasejs/10.7.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/10.7.1/firebase-messaging.js');

// Initialize with your config
firebase.initializeApp({ /* same config */ });

const messaging = firebase.messaging();

messaging.onBackgroundMessage(payload =&amp;gt; {
  console.log('Background message:', payload);
  const notificationTitle = payload.notification.title;
  const notificationOptions = { body: payload.notification.body };
  self.registration.showNotification(notificationTitle, notificationOptions);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register it in your main script: &lt;code&gt;navigator.serviceWorker.register('/firebase-messaging-sw.js');&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; Don't forget to generate VAPID keys in the Firebase console under Cloud Messaging settings. Without them, web push won't work it's a security requirement for browser notifications.&lt;/p&gt;

&lt;p&gt;For accessibility, ensure your notifications include alt text for icons and support screen readers by using semantic titles and bodies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing the Message Flow
&lt;/h2&gt;

&lt;p&gt;Explanations are great, but nothing beats a visual to make things click. Let's build some intuition around how a message travels from your server to a user's device.&lt;/p&gt;

&lt;p&gt;Here's a simplified diagram in chart form:&lt;/p&gt;

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

&lt;p&gt;You can see how FCM acts as the middleman, handling retries and platform quirks so you don't have to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you're debugging, use the Firebase console's Notifications Composer to test flows without server code. It's a lifesaver for visualizing delivery issues early.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real-World Use Case: Chat App Notifications
&lt;/h2&gt;

&lt;p&gt;Theory and setup are fine, but let's apply this to something tangible. Suppose you're building a chat app like Slack or Discord. Users expect instant notifications for new messages, even when the app is closed.&lt;/p&gt;

&lt;p&gt;Here's how FCM fits in: When a user sends a message, your backend (say, a Node.js server) detects it and sends a data message to the recipient's device token. The app then updates the chat UI or shows a custom notification.&lt;/p&gt;

&lt;p&gt;Example server code using the Firebase Admin SDK:&lt;br&gt;
JavaScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const admin = require('firebase-admin');
admin.initializeApp({ /* credentials */ });

function sendChatNotification(toToken, sender, message) {
  const payload = {
    token: toToken,
    data: {
      type: 'chat',
      sender: sender,
      content: message
    }
  };
  admin.messaging().send(payload)
    .then(response =&amp;gt; console.log('Notification sent:', response))
    .catch(error =&amp;gt; console.error('Error:', error));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your client app (web example), handle it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onMessage(messaging, payload =&amp;gt; {
  if (payload.data.type === 'chat') {
    // Update chat UI
    addMessageToUI(payload.data.sender, payload.data.content);
    // Optionally show a notification
    new Notification(`New message from ${payload.data.sender}`, { body: payload.data.content });
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps conversations flowing in real time, boosting engagement. In a production app, you'd store tokens in a database and use topics for group chats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; For chat apps, always handle token refreshes—devices can get new tokens if the app is reinstalled. Miss this, and notifications stop working silently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advanced Tips for FCM&lt;/strong&gt;&lt;br&gt;
Once you're comfortable with basics, let's level up. FCM has features for scaling and customization that can make your notifications smarter.&lt;/p&gt;

&lt;p&gt;First, use topics for broadcast-style messaging. Instead of sending to individual tokens, have devices subscribe to 'news' or 'promos':&lt;/p&gt;

&lt;p&gt;JavaScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Client-side subscribe
getMessaging().subscribeToTopic('news');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then send from server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "Something exciting happened!"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Mistakes and How to Avoid Them
&lt;/h2&gt;

&lt;p&gt;Even pros trip up on FCM. One biggie: Treating tokens like eternal IDs. Tokens can expire or change, so always implement onNewToken handlers to update your server.&lt;/p&gt;

&lt;p&gt;Another: Ignoring platform differences. Android handles background data messages seamlessly, but iOS requires special setup for silent pushes configure your APNs key properly.&lt;/p&gt;

&lt;p&gt;Security slip-ups are common too. Never expose your server key in client code; use the Admin SDK only in trusted environments.&lt;/p&gt;

&lt;p&gt;Finally, over-sending notifications. Users hate spam—use data messages for non-urgent updates to avoid notification fatigue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; If messages aren't delivering, check quotas. FCM limits multicasts to 500 devices per send; batch or use topics for larger groups.&lt;/p&gt;

&lt;p&gt;For UX, make notifications dismissible and respect Do Not Disturb modes.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>api</category>
      <category>learning</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Demystifying Redux Toolkit: A Peek Under the Hood with Plain JavaScript</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Wed, 11 Feb 2026 12:32:35 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/demystifying-redux-toolkit-a-peek-under-the-hood-with-plain-javascript-378b</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/demystifying-redux-toolkit-a-peek-under-the-hood-with-plain-javascript-378b</guid>
      <description>&lt;p&gt;A hands-on exploration of how Redux Toolkit simplifies state management while building on core JavaScript and Redux principles.&lt;/p&gt;

&lt;p&gt;Hey there! If you've ever wrestled with Redux in a real-world app, you know it can feel like a beast boilerplate code everywhere, actions flying left and right, and reducers that grow like weeds. That's where Redux Toolkit swoops in like a friendly sidekick, cutting the cruft and letting you focus on what matters: building features.&lt;/p&gt;

&lt;p&gt;In this guide, we'll pull back the curtain on how Redux Toolkit actually works underneath, all rooted in vanilla JavaScript and Redux fundamentals. You'll learn why it's not magic, but smart abstractions that make your code cleaner and more maintainable. By the end, you'll be able to spot the JavaScript patterns powering it, troubleshoot issues with confidence, and even roll your own simplifications if needed. Whether you're a Redux newbie or a seasoned pro, this will level up your mental model. Let's dive in!&lt;/p&gt;

&lt;p&gt;Table of Contents&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Basics: What Redux Toolkit Is (and Isn't)&lt;/li&gt;
&lt;li&gt;Practical Example: Building a Simple Slice&lt;/li&gt;
&lt;li&gt;Visual Intuition: Data Flow Under the Covers&lt;/li&gt;
&lt;li&gt;Real-World Use Case: Managing Async Data&lt;/li&gt;
&lt;li&gt;Advanced Tips: Customizing and Extending&lt;/li&gt;
&lt;li&gt;Common Mistakes: Pitfalls to Avoid&lt;/li&gt;
&lt;li&gt;Wrapping It Up&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Basics: What Redux Toolkit Is (and Isn't)
&lt;/h2&gt;

&lt;p&gt;Let's start simple. Redux Toolkit isn't a complete rewrite of Redux it's a set of utilities built right on top of it, designed to reduce boilerplate and enforce best practices. At its heart, it's all JavaScript: functions, objects, and immutable updates.&lt;br&gt;
Why does this matter? In vanilla Redux, you'd manually create action types as strings, write action creators as functions, and build reducers with switch statements. It's error-prone and verbose. Redux Toolkit wraps these in higher-level APIs like &lt;code&gt;createSlice&lt;/code&gt;, which generates all that for you under the hood.&lt;br&gt;
For instance, &lt;code&gt;createSlice&lt;/code&gt;takes an object with your initial state, reducers, and a name. It returns a slice object with actions and a reducer. But underneath? It's using plain JS to create action types (like &lt;code&gt;${sliceName}/reducerName)&lt;/code&gt;, action creators (functions that return { type, payload }), and a reducer function that uses Immer for immutable updates without you mutating state directly.&lt;/p&gt;

&lt;p&gt;Here's a bare bones peek at what createSlice might look like if we simplified it in JS (this is conceptual, not the actual source):&lt;/p&gt;

&lt;p&gt;Javascript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function createSlice({ name, initialState, reducers }) {
  const actions = {};
  const reducerCases = {};

  for (const [reducerName, reducerFn] of Object.entries(reducers)) {
    const type = `${name}/${reducerName}`;
    actions[reducerName] = (payload) =&amp;gt; ({ type, payload });
    reducerCases[type] = reducerFn;
  }

  const reducer = (state = initialState, action) =&amp;gt; {
    const handler = reducerCases[action.type];
    return handler ? handler(state, action) : state;
  };

  return { reducer, actions };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See? No sorcery just object iteration, string templates, and a reducer switch equivalent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tips:&lt;/strong&gt; A common gotcha for beginners is thinking Redux Toolkit "&lt;strong&gt;mutates&lt;/strong&gt;" state. It doesn't! It uses Immer.js to let you write mutable-looking code in reducers, but it produces immutable updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Always remember:&lt;/strong&gt; under the hood, it's enforcing Redux's immutability rule to prevent bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Example: Building a Simple Slice
&lt;/h2&gt;

&lt;p&gt;Alright, you've got the theory let's apply it. Imagine you're building a todo app. In vanilla Redux, you'd need separate files for actions and reducers, plus a bunch of constants. With Toolkit, it's one createSlice call.&lt;/p&gt;

&lt;p&gt;First, install it (assuming you're in a React project): &lt;code&gt;npm install @reduxjs/toolkit&lt;/code&gt;.&lt;br&gt;
Now, create a slice for todos:&lt;/p&gt;

&lt;p&gt;Javascript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createSlice } from '@reduxjs/toolkit';

const todosSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    addTodo: (state, action) =&amp;gt; {
      state.push(action.payload); // Looks mutable, but Immer handles it!
    },
    toggleTodo: (state, action) =&amp;gt; {
      const todo = state.find(t =&amp;gt; t.id === action.payload);
      if (todo) todo.completed = !todo.completed;
    },
  },
});

export const { addTodo, toggleTodo } = todosSlice.actions;
export default todosSlice.reducer;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Underneath, &lt;code&gt;configureStore&lt;/code&gt;is just a wrapper around Redux's &lt;code&gt;createStore&lt;/code&gt;, but it adds middleware like Redux Thunk by default and enables DevTools. In JS terms, it's combining reducers with &lt;code&gt;combineReducers&lt;/code&gt;and applying enhancers.&lt;/p&gt;

&lt;p&gt;To use it in a component:&lt;/p&gt;

&lt;p&gt;JSX&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useSelector, useDispatch } from 'react-redux';
import { addTodo } from './todosSlice';

function TodoList() {
  const todos = useSelector(state =&amp;gt; state.todos);
  const dispatch = useDispatch();

  return (
    &amp;lt;ul&amp;gt;
      {todos.map(todo =&amp;gt; &amp;lt;li key={todo.id}&amp;gt;{todo.text}&amp;lt;/li&amp;gt;)}
      &amp;lt;button onClick={() =&amp;gt; dispatch(addTodo({ id: Date.now(), text: 'New todo' }))}&amp;gt;
        Add Todo
      &amp;lt;/button&amp;gt;
    &amp;lt;/ul&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works because dispatching &lt;code&gt;addTodo&lt;/code&gt;sends an action like &lt;code&gt;{ type: 'todos/addTodo', payload: { ... } },&lt;/code&gt; which the reducer handles immutably.&lt;/p&gt;

&lt;p&gt;Don't forget to export both actions and the reducer! Beginners often miss this, leading to "undefined action" errors. Also, if you're coming from vanilla Redux, resist the urge to write switch statements Toolkit discourages it for good reason.&lt;/p&gt;

&lt;p&gt;let's visualize the flow next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual Intuition: Data Flow Under the Covers
&lt;/h2&gt;

&lt;p&gt;Pictures help, right? Let's build some mental imagery for how data moves in Redux Toolkit, all powered by JS patterns.&lt;/p&gt;

&lt;p&gt;At the core is unidirectional data flow: Components dispatch actions → Store updates via reducers → Components re-render with new state.&lt;/p&gt;

&lt;p&gt;Underneath, when you call &lt;code&gt;dispatch(addTodo(payload))&lt;/code&gt;, it's a plain function call. The action creator returns an object, the middleware (like Thunk) processes it if async, then the root reducer delegates to your slice reducer.&lt;br&gt;
Think of it like a JS event bus: The store is an object with &lt;code&gt;dispatch&lt;/code&gt;, &lt;code&gt;subscribe&lt;/code&gt;, and &lt;code&gt;getState&lt;/code&gt;methods. &lt;code&gt;configureStore&lt;/code&gt;sets this up with enhancers for debugging.&lt;/p&gt;

&lt;p&gt;For visual intuition, imagine a flowchart:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Action dispatched → Middleware chain (array of functions, each calling next).&lt;/li&gt;
&lt;li&gt;Reducer called → Uses JS Object.assign or spread for immutability (via Immer).&lt;/li&gt;
&lt;li&gt;Subscribers notified → React-Redux's useSelector hooks trigger re-renders.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a simplified JS mimic of the store's dispatch loop:&lt;/p&gt;

&lt;p&gt;Javascript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function createSimpleStore(reducer, initialState) {
  let state = initialState;
  const listeners = [];

  function dispatch(action) {
    state = reducer(state, action); // Immutable update here
    listeners.forEach(listener =&amp;gt; listener());
  }

  function subscribe(listener) {
    listeners.push(listener);
    return () =&amp;gt; listeners.splice(listeners.indexOf(listener), 1);
  }

  function getState() {
    return state;
  }

  return { dispatch, subscribe, getState };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Toolkit adds layers like auto-batching updates for performance.&lt;br&gt;
&lt;strong&gt;Tip Box:&lt;/strong&gt; For accessibility, ensure your app's state changes don't break keyboard navigation use ARIA live regions if toasts or modals rely on Redux state. It's a small UX win that Toolkit doesn't handle automatically.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>learning</category>
      <category>programming</category>
    </item>
    <item>
      <title>Mastering Smooth Page Transitions with the View Transitions API in 2026</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Tue, 10 Feb 2026 13:15:56 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/mastering-smooth-page-transitions-with-the-view-transitions-api-in-2026-31of</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/mastering-smooth-page-transitions-with-the-view-transitions-api-in-2026-31of</guid>
      <description>&lt;p&gt;You've built a beautiful React app. The data flows, the components are crisp, but every page change feels... abrupt. A flash of white, a jarring jump, maybe some custom Framer Motion wizardry that adds 50kb and still stutters on mobile. Sound familiar?&lt;/p&gt;

&lt;p&gt;In 2026, users expect native-app polish on the web. The View Transitions API — now widely supported across major browsers changes the game. It lets the browser handle smooth, hardware-accelerated transitions between DOM states or even full page navigations, with minimal code.&lt;/p&gt;

&lt;p&gt;By the end of this post, you'll know exactly how to add buttery smooth transitions to your SPA (or MPA!), understand why it outperforms custom solutions, and avoid the gotchas that trip up most developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why View Transitions Matter in Real Apps&lt;/li&gt;
&lt;li&gt;The Basic Concept: How the Browser Takes Over&lt;/li&gt;
&lt;li&gt;Implementing Same-Document Transitions in React&lt;/li&gt;
&lt;li&gt;Cross-Document Magic: MPAs Without Frameworks&lt;/li&gt;
&lt;li&gt;Customizing with view-transition-name&lt;/li&gt;
&lt;li&gt;Advanced Patterns and Performance Wins&lt;/li&gt;
&lt;li&gt;Common Mistakes and Gotchas&lt;/li&gt;
&lt;li&gt;Wrapping Up: Level Up Your App's Feel&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why View Transitions Matter in Real Apps
&lt;/h2&gt;

&lt;p&gt;Modern users switch between apps that feel alive: iOS/Android apps slide, morph, and fade with zero perceived latency. Web apps? Often still feel like... documents.&lt;br&gt;
The View Transitions API bridges that gap. It captures snapshots of old + new states, animates them natively, and updates the DOM in between all while keeping focus, accessibility, and performance intact.&lt;/p&gt;

&lt;p&gt;In real projects (dashboards, e-commerce, admin panels), this reduces cognitive load and makes your app feel 10x more premium. Best part? It's a browser feature — no React-specific hacks needed.&lt;/p&gt;

&lt;p&gt;The Basic Concept: How the Browser Takes Over&lt;br&gt;
The magic happens in two steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The browser snapshots the current DOM (old view).&lt;/li&gt;
&lt;li&gt;You update the DOM.&lt;/li&gt;
&lt;li&gt;The browser snapshots the new DOM and animates between them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Default behavior:&lt;/strong&gt; a smooth cross-fade.&lt;/p&gt;

&lt;p&gt;Javascript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Vanilla JS trigger
document.startViewTransition(() =&amp;gt; {
  // Update your DOM here — React can do this too!
  updateMyUI(newState);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, it creates pseudo-elements like &lt;code&gt;::view-transition-old(root)&lt;/code&gt; and &lt;code&gt;::view-transition-new(root)&lt;/code&gt; for CSS animation control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Same-Document Transitions in React
&lt;/h2&gt;

&lt;p&gt;In React SPAs (React Router, custom navigation), wrap route changes in &lt;code&gt;startViewTransition&lt;/code&gt;.&lt;br&gt;
Here's a practical hook:&lt;/p&gt;

&lt;p&gt;jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useTransition } from 'react';

function useViewTransition() {
  const navigateWithTransition = (callback) =&amp;gt; {
    if (!document.startViewTransition) {
      callback();
      return;
    }

    document.startViewTransition(() =&amp;gt; {
      // React 18+ handles this suspendable
      callback();
    });
  };

  return navigateWithTransition;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage in a component:&lt;br&gt;
Jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const navigate = useViewTransition();

&amp;lt;button
  onClick={() =&amp;gt; navigate(() =&amp;gt; setPage('details'))}
&amp;gt;
  Go to Details
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Accessibility Note:&lt;/strong&gt;&lt;br&gt;
The API preserves focus and doesn't disrupt screen readers — huge win over custom animations!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt;&lt;br&gt;
Combine with React's useTransition for pending states during data fetches.&lt;/p&gt;
&lt;h2&gt;
  
  
  Cross-Document Magic: MPAs Without Frameworks
&lt;/h2&gt;

&lt;p&gt;For static sites, Astro, or plain HTML add this CSS to both pages:&lt;/p&gt;

&lt;p&gt;CSS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@view-transition {
  navigation: auto;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Page navigations now fade smoothly. No JS required!&lt;br&gt;
For React + Next.js App Router, it's automatic in recent versions, but you can customize.&lt;/p&gt;
&lt;h2&gt;
  
  
  Customizing with view-transition-name
&lt;/h2&gt;

&lt;p&gt;The real power: name elements to animate specifically (morphing cards, expanding images).&lt;/p&gt;

&lt;p&gt;CSS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.product-card {
  view-transition-name: product-1;
  contain: paint; /* Important for isolation */
}

.product-detail img {
  view-transition-name: product-1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser auto-animates position, size, opacity no keyframes needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt;&lt;br&gt;
Use dynamic names in React: &lt;code&gt;view-transition-name: product-${id};&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Patterns and Performance Wins
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Group animations with view-transition-class&lt;/li&gt;
&lt;li&gt;Custom keyframes on ::view-transition-old(...)&lt;/li&gt;
&lt;li&gt;Types for conditional transitions: @view-transition { types: slide; }&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Performance: Native → GPU-accelerated, tiny overhead vs. libraries like GSAP.&lt;br&gt;
In benchmarks, apps with View Transitions feel 2–3x snappier on low-end devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes and Gotchas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Forgetting fallbacks — always check support.&lt;/li&gt;
&lt;li&gt;Mutating DOM outside the callback → broken snapshots.&lt;/li&gt;
&lt;li&gt;Using with heavy SSR mismatches → hydration errors.&lt;/li&gt;
&lt;li&gt;Ignoring &lt;code&gt;contain: paint/layout&lt;/code&gt; → animation glitches.&lt;/li&gt;
&lt;li&gt;Over-customizing defaults — the built-in crossfade is often best.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Accessibility Note:&lt;/strong&gt;&lt;br&gt;
Test with reduced motion (&lt;code&gt;prefers-reduced-motion&lt;/code&gt;) — disable or simplify transitions.&lt;/p&gt;

&lt;p&gt;🧩 Further Reading:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API" rel="noopener noreferrer"&gt;MDN View Transitions API&lt;/a&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API" rel="noopener noreferrer"&gt;Chrome for Developers: Smooth transitions with the View Transitions API&lt;/a&gt;&lt;br&gt;
Personal takeaway: Sometimes the best DX comes from leaning on the platform — the web is getting pretty magical again. 🚀&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>learning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why Solid.js Might Be the Most Underrated Frontend Superpower in 2026 (And How to Start Using It Today)</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Tue, 20 Jan 2026 12:16:33 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/why-solidjs-might-be-the-most-underrated-frontend-superpower-in-2025-and-how-to-start-using-it-3j77</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/why-solidjs-might-be-the-most-underrated-frontend-superpower-in-2025-and-how-to-start-using-it-3j77</guid>
      <description>&lt;p&gt;Hey fellow frontend devs, let's be real for a second.&lt;/p&gt;

&lt;p&gt;You're building yet another dashboard or e-commerce app. You fire up React (or Next.js because SSR is non-negotiable in 2026), write some components, throw in useState/useEffect everywhere, and suddenly your bundle is ballooning, re-renders are happening like fireworks, and your Lighthouse score is crying in the corner.&lt;br&gt;
Sound familiar?&lt;/p&gt;

&lt;p&gt;In 2026, the conversation has shifted. While React remains the king of ecosystems and job listings, and Svelte keeps winning hearts with its "write less, do more" compiler magic, there's a quiet powerhouse that's been stealing benchmarks and developer minds: &lt;strong&gt;Solid.js&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's like React's reactivity model but without the virtual DOM tax, delivering React like ergonomics with Svelte-level performance. If you've been sleeping on Solid.js, 2026 is the year to wake up.&lt;br&gt;
In this post, I'll break down why Solid.js feels like the perfect "future proof" choice right now, how its fine-grained reactivity works under the hood, and give you a practical starter guide with real code examples.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Pain Point: React's Hidden Cost in 2026
&lt;/h2&gt;

&lt;p&gt;React's virtual DOM diffing was revolutionary in 2013. But in 2026, with massive apps, concurrent features, and Server Components, we still pay a price:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unnecessary re-renders cascade through component trees&lt;/li&gt;
&lt;li&gt;Bundle sizes creep up with client-side hydration&lt;/li&gt;
&lt;li&gt;Profiling tools become your best friend (and worst enemy)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alternatives like Svelte compile away the framework entirely, and Qwik resumable architecture skips hydration drama. But many of us love React's mental model hooks, JSX, unidirectional data flow.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;Solid.js&lt;/strong&gt;: It gives you the best of both worlds.&lt;/p&gt;

&lt;p&gt;Solid.js uses &lt;strong&gt;fine-grained reactivity&lt;/strong&gt; with signals (inspired by libraries like MobX or Preact Signals, but baked in). Instead of re-rendering entire components, Solid updates only the DOM nodes that actually changed.&lt;/p&gt;

&lt;p&gt;Think of it like this analogy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React is like repainting an entire room every time someone moves a chair.&lt;/li&gt;
&lt;li&gt;Solid.js is like having smart paint that only refreshes the exact spot where the chair moved.&lt;/li&gt;
&lt;li&gt;Result? Blazing-fast updates, tiny runtime (~7-10KB gzipped), and no VDOM overhead.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How Solid.js Reactivity Actually Works (No Magic, Just Signals)
&lt;/h2&gt;

&lt;p&gt;At its core, Solid uses primitives like &lt;code&gt;createSignal&lt;/code&gt;, &lt;code&gt;createEffect&lt;/code&gt;, and &lt;code&gt;createMemo&lt;/code&gt;.&lt;br&gt;
Here's a simple counter example:&lt;br&gt;
tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createSignal, createEffect } from 'solid-js';

function Counter() {
  const [count, setCount] = createSignal(0);

  // This effect runs only when count changes
  createEffect(() =&amp;gt; {
    console.log(`Count is now: ${count()}`);
  });

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Count: {count()}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count() + 1)}&amp;gt;
        Increment
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice something missing? No &lt;code&gt;useState&lt;/code&gt;+ &lt;code&gt;useEffect&lt;/code&gt; dependency array hell.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;count()&lt;/code&gt; is a getter that tracks dependencies automatically&lt;/li&gt;
&lt;li&gt;Updates are surgical — only the text node inside &lt;code&gt;{count()}&lt;/code&gt; re-renders&lt;/li&gt;
&lt;li&gt;No component re-execution unless signals force it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For derived state, use &lt;code&gt;createMemo&lt;/code&gt;:&lt;br&gt;
tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [firstName, setFirstName] = createSignal('Krish');
const [lastName, setLastName] = createSignal('Dev');

const fullName = createMemo(() =&amp;gt; `${firstName()} ${lastName()}`);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fullName()&lt;/code&gt; recomputes only when firstName or lastName changes no wasteful recalculations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tailwind + Solid.js = Developer Joy in 2026
&lt;/h2&gt;

&lt;p&gt;Pair it with** Tailwind CSS v4 &lt;strong&gt;(now even faster with native Oxide engine) and you get utility classes that feel native in Solid's JSX.&lt;br&gt;
Add **Vite + solid-js/vite plugin&lt;/strong&gt;, and your dev server is instant. No more waiting for HMR in large React apps.&lt;/p&gt;

&lt;p&gt;Pros in 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unmatched runtime performance (often beats Svelte in fine-grained updates)&lt;/li&gt;
&lt;li&gt;React-like syntax (easy transition for React devs)&lt;/li&gt;
&lt;li&gt;Tiny runtime, zero VDOM&lt;/li&gt;
&lt;li&gt;Growing ecosystem: SolidStart (full-stack like Next.js), stores, primitives, etc.&lt;/li&gt;
&lt;li&gt;TypeScript first-class&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller community than React (but growing fast in 2026)&lt;/li&gt;
&lt;li&gt;Fewer ready-made component libraries (but Headless UI + Tailwind works great)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In 2026, frontend isn't about picking "&lt;strong&gt;the one true framework&lt;/strong&gt;" anymore. It's about choosing the right tool for the job. If performance, clean reactivity, and modern DX matter to you (and they should), give &lt;strong&gt;Solid.js&lt;/strong&gt; a weekend. You might just find your new favorite.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>solidjs</category>
      <category>react</category>
      <category>learning</category>
    </item>
    <item>
      <title>React Server Components + TanStack Query: The 2026 Data-Fetching Power Duo You Can't Ignore🧑‍💻⌨️</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Mon, 19 Jan 2026 16:29:46 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/react-server-components-tanstack-query-the-2026-data-fetching-power-duo-you-cant-ignore-21fj</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/react-server-components-tanstack-query-the-2026-data-fetching-power-duo-you-cant-ignore-21fj</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction: The Eternal Data-Fetching Struggle Is (Almost) Over&lt;/strong&gt;&lt;br&gt;
If you've been building React apps for any amount of time, you know the pain: fetch data on the client → show loading spinner → handle errors → cache it somehow → refetch on focus → pray the UI doesn't flicker. In 2024, we threw TanStack Query (formerly React Query) at the problem and it worked wonders. But in 2026, React Server Components (RSC) arrived like a plot twist nobody saw coming suddenly, data can live on the server, zero client JS for static parts, and streaming renders that feel magical.&lt;/p&gt;

&lt;p&gt;The real game-changer? Combining React Server Components with TanStack Query. This duo gives you the best of both worlds: lightning fast initial loads from the server + smart, optimistic client-side caching, mutations, and background refetches. It's not either/or anymore it's the hybrid architecture that's powering the fastest, most maintainable React apps today.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why This Combo Wins in 2026
&lt;/h2&gt;

&lt;p&gt;Frontend performance in 2026 isn't optional Google's Core Web Vitals are stricter, users bounce if LCP &amp;gt; 2.5s, and SEO demands fast Time to First Byte.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Server Components&lt;/strong&gt; fetch data on the server, render HTML/streamed UI, and send zero JS for those parts. Perfect for staticish content like product lists or dashboards.&lt;br&gt;
&lt;strong&gt;TanStack Query&lt;/strong&gt; handles client-side needs: infinite scrolling, mutations with optimistic UI, stale while revalidate, deduping requests, and background sync.&lt;/p&gt;

&lt;p&gt;Together, they eliminate waterfalls, reduce bundle size, and give you fine grained control.&lt;br&gt;
Real-world impact? Teams report 40-70% faster initial loads and dramatically lower TTI when migrating legacy React apps to this pattern.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pattern 1: Server Components for Initial Data + TanStack Query for Interactivity
&lt;/h2&gt;

&lt;p&gt;This is the most common 2026 pattern in Next.js 15+ apps.&lt;br&gt;
Imagine a dashboard showing user stats:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Server fetches core data → renders static UI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Client uses TanStack Query for live updates, filters, or mutations.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// app/dashboard/page.tsx (Server Component)
import { getUserStats } from '@/lib/api';

export default async function Dashboard() {
  const initialStats = await getUserStats(); // Runs on server, no client JS

  return (
    &amp;lt;div className="p-6"&amp;gt;
      &amp;lt;h1 className="text-3xl font-bold"&amp;gt;Your Dashboard&amp;lt;/h1&amp;gt;
      &amp;lt;StaticStats initialStats={initialStats} /&amp;gt;
      &amp;lt;InteractiveCharts /&amp;gt; {/* Client component */}
    &amp;lt;/div&amp;gt;
  );
}

// components/StaticStats.tsx (Server Component - passed props)
function StaticStats({ initialStats }: { initialStats: UserStats }) {
  return (
    &amp;lt;div className="grid grid-cols-3 gap-4 mt-6"&amp;gt;
      &amp;lt;StatCard title="Total Revenue" value={`$${initialStats.revenue}`} /&amp;gt;
      {/* more cards */}
    &amp;lt;/div&amp;gt;
  );
}

// components/InteractiveCharts.tsx (Client Component)
'use client';

import { useQuery } from '@tanstack/react-query';
import { fetchLiveStats } from '@/lib/api';

export function InteractiveCharts() {
  const { data, isLoading } = useQuery({
    queryKey: ['liveStats'],
    queryFn: fetchLiveStats,
    initialData: initialStats, // from server props (passed via context or prop drilling)
    staleTime: 30 * 1000, // 30s freshness
  });

  if (isLoading) return &amp;lt;div&amp;gt;Updating...&amp;lt;/div&amp;gt;;

  return (
    // Chart with live data, optimistic updates on filters, etc.
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it rocks:&lt;/strong&gt; Server delivers fully-rendered HTML instantly. TanStack Query kicks in for interactivity without duplicating fetches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 2: Mutations &amp;amp; Optimistic Updates – The Killer Feature
&lt;/h2&gt;

&lt;p&gt;Server Components can't mutate (they're async functions, not interactive). TanStack Query shines here.&lt;/p&gt;

&lt;p&gt;Example: Like button on a post.&lt;br&gt;
tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client';

import { useMutation, useQueryClient } from '@tanstack/react-query';

function LikeButton({ postId, initialLikes }: { postId: string; initialLikes: number }) {
  const queryClient = useQueryClient();

  const mutation = useMutation({
    mutationFn: () =&amp;gt; likePost(postId),
    onMutate: async () =&amp;gt; {
      // Optimistic update
      await queryClient.cancelQueries({ queryKey: ['post', postId] });
      const previous = queryClient.getQueryData(['post', postId]);
      queryClient.setQueryData(['post', postId], (old: any) =&amp;gt; ({
        ...old,
        likes: old.likes + 1,
      }));
      return { previous };
    },
    onError: (err, vars, context) =&amp;gt; {
      queryClient.setQueryData(['post', postId], context?.previous);
    },
    onSettled: () =&amp;gt; {
      queryClient.invalidateQueries({ queryKey: ['post', postId] });
    },
  });

  return (
    &amp;lt;button
      onClick={() =&amp;gt; mutation.mutate()}
      className="flex items-center gap-2"
      disabled={mutation.isPending}
    &amp;gt;
      ❤️ {initialLikes + (mutation.isPending ? 1 : 0)}
    &amp;lt;/button&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server component provides &lt;code&gt;initialLikes&lt;/code&gt;, TanStack Query handles the rest optimistic UI, rollback on error, and refetch.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use What: Decision Guide
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pure Server Components (RSC only)&lt;/strong&gt; — Landing pages, blogs, marketing sites. Zero JS, max speed.&lt;br&gt;
&lt;strong&gt;TanStack Query only&lt;/strong&gt;— Highly interactive SPAs (admin panels, real-time apps).&lt;br&gt;
&lt;strong&gt;Hybrid (RSC + TanStack Query)&lt;/strong&gt; — Most modern apps: dashboards, e-commerce, SaaS. Best DX and perf in 2025.&lt;/p&gt;

&lt;p&gt;Pro tip: Use Next.js or TanStack Start for seamless integration. Both support RSC natively in 2026.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actionable Takeaways &amp;amp; Next Steps&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start small:-&lt;/strong&gt; Migrate one page to Server Components + pass initial data to client queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adopt TanStack Query v5+ :-&lt;/strong&gt;  It has better RSC support and suspense integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure everything :-&lt;/strong&gt; Use Vercel Analytics or Web Vitals to track LCP/TTI before/after.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Experiment :-&lt;/strong&gt; Build a side project with Next.js 15 + TanStack Query. You'll feel the difference immediately.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The frontend world moved fast in 2026, but this combo feels like the "right" architecture for the next few years fast, scalable, and actually fun to build with.&lt;br&gt;
What do you think are you all in on Server Components yet, or still team TanStack Query client-side? Drop your thoughts in the comments!&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>learning</category>
    </item>
    <item>
      <title>The React Compiler Just Made Your Memoization Skills Obsolete, Here's What to Do Next</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Sat, 17 Jan 2026 03:47:40 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/the-react-compiler-just-made-your-memoization-skills-obsolete-heres-what-to-do-next-44pf</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/the-react-compiler-just-made-your-memoization-skills-obsolete-heres-what-to-do-next-44pf</guid>
      <description>&lt;p&gt;Hey friend,&lt;br&gt;
Remember that moment when your beautifully crafted React component starts re-rendering like it's auditioning for a fireworks show? You dig in, sprinkle &lt;code&gt;useMemo&lt;/code&gt;and &lt;code&gt;useCallback&lt;/code&gt;everywhere, wrap things in &lt;code&gt;React.memo&lt;/code&gt;, and pray the performance gods smile upon you.&lt;br&gt;
Then you ship it… and discover one rogue prop is still causing the whole subtree to explode.&lt;br&gt;
Yeah. We've all been there.&lt;/p&gt;

&lt;p&gt;In 2026, that entire song and dance routine is quietly becoming optional. Meta dropped React Compiler 1.0 late last year, and it's changing the game for anyone building serious React apps. No more manual memoization gymnastics in most cases the compiler does it for you at build time.&lt;/p&gt;

&lt;p&gt;But here's the twist: this freedom comes with new responsibilities. You can't just flip the switch and forget everything you know about React's rendering model. In fact, understanding why the compiler works (and when it doesn't) has become one of the highest leverage skills for frontend engineers this year.&lt;/p&gt;

&lt;p&gt;In this post, you'll learn:&lt;/p&gt;

&lt;p&gt;What React Compiler actually does under the hood&lt;br&gt;
How to adopt it progressively without breaking your app&lt;br&gt;
The mental model shift from manual optimization → compiler-friendly code&lt;br&gt;
Real patterns that still need your attention (because the compiler isn't magic)&lt;/p&gt;

&lt;p&gt;Let's dive in.&lt;/p&gt;
&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Old World: Why Memoization Used to Hurt&lt;/li&gt;
&lt;li&gt;Meet React Compiler: Your New Silent Partner&lt;/li&gt;
&lt;li&gt;How It Actually Works (Intuition + Visual)&lt;/li&gt;
&lt;li&gt;Practical Migration: From Legacy to Compiler-Ready&lt;/li&gt;
&lt;li&gt;Gotchas &amp;amp; Advanced Patterns That Still Matter&lt;/li&gt;
&lt;li&gt;Real-World Wins: Where It's Saving Teams Time &amp;amp; Bundle Size&lt;/li&gt;
&lt;li&gt;The New Mental Model: Write Simple, Let It Optimize&lt;/li&gt;
&lt;li&gt;Summary &amp;amp; Next Steps&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Old World: Why Memoization Used to Hurt
&lt;/h2&gt;

&lt;p&gt;Before the compiler, React performance was a discipline problem.&lt;br&gt;
Every render could cascade down the tree. Props change → children re-render → grandchildren re-render → tears.&lt;br&gt;
So we fought back with:&lt;/p&gt;

&lt;p&gt;tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Classic stabilization
const expensiveValue = useMemo(() =&amp;gt; computeHeavyThing(data), [data]);

const handleClick = useCallback(() =&amp;gt; {
  // do stuff
}, []); // empty deps? Careful!

const MemoChild = React.memo(ChildComponent);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This worked… until it didn't. Forget a dep? Infinite loop. Add too many? Over-optimization tax on readability.&lt;/p&gt;

&lt;p&gt;Note:-Manual memoization is like defensive driving — useful, but exhausting when you do it for every mile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet React Compiler: Your New Silent Partner
&lt;/h2&gt;

&lt;p&gt;React Compiler (formerly "React Forget") is a Babel plugin + build-time optimizer. It analyzes your components statically and automatically inserts the &lt;code&gt;useMemo&lt;/code&gt;/&lt;code&gt;useCallback&lt;/code&gt;/&lt;code&gt;React.memo&lt;/code&gt; wrappers you would have written… but smarter.&lt;/p&gt;

&lt;p&gt;Key promises:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fine-grained reactivity without manual effort&lt;/li&gt;
&lt;li&gt;No runtime overhead (optimizations happen at build)&lt;/li&gt;
&lt;li&gt;Works with hooks, components, and custom hooks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the docs: it turns "naive" code into optimized code automatically.&lt;/p&gt;

&lt;p&gt;tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Before compiler: manual everything
function TodoList({ todos }) {
  const sortedTodos = useMemo(() =&amp;gt; [...todos].sort(), [todos]);
  // ...
}

// After compiler: just write clean code
function TodoList({ todos }) {
  const sortedTodos = [...todos].sort(); // ← Compiler memos this!
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler figures out dependencies and memoizes where safe.&lt;br&gt;
&lt;strong&gt;Accessibility Note:&lt;/strong&gt; Cleaner code = fewer bugs = better a11y outcomes. Win-win.&lt;/p&gt;
&lt;h3&gt;
  
  
  How It Actually Works (Intuition + Visual)
&lt;/h3&gt;

&lt;p&gt;Think of the compiler as a super-smart linter that rewrites your render function.&lt;br&gt;
It tracks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What values are "pure" (no side effects)&lt;/li&gt;
&lt;li&gt;Which deps they depend on&lt;/li&gt;
&lt;li&gt;Where mutations could break things&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then it injects memoization only where needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnd5342z5w32jfxsiv873.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnd5342z5w32jfxsiv873.png" alt="A river represents a component tree. On the left, upstream changes create a flood that rushes through everything downstream. On the right, a compiler places small “memo” dams along the river, breaking the flow and keeping downstream areas calm by stopping unnecessary re-renders." width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Practical Migration: From Legacy to Compiler-Ready
&lt;/h2&gt;

&lt;p&gt;Don't enable it globally on day one that's a recipe for frustration.&lt;/p&gt;

&lt;p&gt;Step-by-step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install &amp;amp; configure (Next.js, Vite, Expo all have first-class support in 2026)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bash&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install babel-plugin-react-compiler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add to babel.config:&lt;br&gt;
Javascript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plugins: [
  ['babel-plugin-react-compiler', { target: '19' }]
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Use incremental adoption: 'use no memo' directive to opt-out of problematic files.
tsx:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use no memo'; // Compiler skips this component

function TrickyComponent() { ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run ESLint with compiler plugin — it catches things that block optimization early.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Advanced Patterns That Still Matter
&lt;/h2&gt;

&lt;p&gt;The compiler isn't perfect (yet). Watch for:&lt;/p&gt;

&lt;p&gt;Side effects in render — &lt;code&gt;console.log&lt;/code&gt; inside render? Compiler may bail.&lt;br&gt;
Complex mutations — If you mutate props/objects directly, it can't guarantee safety.&lt;br&gt;
Dynamic deps — Things like &lt;code&gt;useMemo(() =&amp;gt; fn(dep ? a : b), [dep])&lt;/code&gt; can confuse it.&lt;/p&gt;

&lt;p&gt;Common mistake:&lt;br&gt;
tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Compiler might not optimize this well
const value = expensiveCalc(props.data?.nested?.deep);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const data = props.data;
const value = expensiveCalc(data?.nested?.deep);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, &lt;strong&gt;Server Components&lt;/strong&gt; + Compiler = rocket fuel. Use them together for insane perf.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Wins: Where It's Saving Teams Time &amp;amp; Bundle Size
&lt;/h2&gt;

&lt;p&gt;Teams adopting it report:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;20-40% reduction in manual memo code&lt;/li&gt;
&lt;li&gt;Noticeably smoother UIs in large lists/dashboards&lt;/li&gt;
&lt;li&gt;Faster onboarding: juniors write simple code, compiler handles perf&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One case study saw homepage render time drop 35% with zero manual changes after cleanup.&lt;/p&gt;

&lt;h2&gt;
  
  
  The New Mental Model: Write Simple, Let It Optimize
&lt;/h2&gt;

&lt;p&gt;Shift your focus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write straightforward, declarative code&lt;/li&gt;
&lt;li&gt;Avoid unnecessary side effects in render&lt;/li&gt;
&lt;li&gt;Lean on ESLint + compiler feedback&lt;/li&gt;
&lt;li&gt;Optimize intentionally only when profiler says so&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're no longer the performance janitor you're the architect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;React Compiler isn't about replacing your skills; it's about elevating them. The tedious parts are automated, so you can focus on architecture, DX, and user experience.&lt;br&gt;
Next steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Try it on a small feature branch today&lt;/li&gt;
&lt;li&gt;Add the ESLint plugin — treat warnings as build errors&lt;/li&gt;
&lt;li&gt;Pair it with Server Components for maximum impact&lt;/li&gt;
&lt;li&gt;Profile before &amp;amp; after — numbers don't lie&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the year React performance becomes boring (in a good way).&lt;/p&gt;

&lt;p&gt;If this helped you level up, share it with a friend still drowning in &lt;code&gt;useMemo&lt;/code&gt;. And stay tuned — next I'll dive into how Server Actions + Compiler are killing traditional state management.&lt;/p&gt;

&lt;p&gt;Until then, keep shipping fast &amp;amp; smooth ✨&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>programming</category>
      <category>coding</category>
    </item>
    <item>
      <title>Mastering React Server Components: The 2026 Way to Build Blazing Fast Apps Without the Hydration Tax</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Fri, 16 Jan 2026 03:39:05 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/mastering-react-server-components-the-2026-way-to-build-blazing-fast-apps-without-the-hydration-tax-25mi</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/mastering-react-server-components-the-2026-way-to-build-blazing-fast-apps-without-the-hydration-tax-25mi</guid>
      <description>&lt;p&gt;Imagine you're building a dashboard for an e-commerce admin panel. Hundreds of products, user analytics, real-time stats. You fetch everything on the client, throw in a few &lt;code&gt;useEffect&lt;/code&gt;calls, and suddenly your bundle balloons to 200KB+ of JavaScript. Users on slow connections wait... and wait... while the spinner spins.&lt;/p&gt;

&lt;p&gt;We've all been there. The hydration tax hurts. In 2026, React Server Components (RSCs) change the game completely. They let you run components entirely on the server, send HTML to the client, and only "wake up" the interactive parts with minimal JS. The result? Faster initial loads, better SEO, and a mental model that feels refreshingly simple once it clicks.&lt;br&gt;
In this post, you'll learn exactly how RSCs work, when to use them, practical patterns with Next.js App Router, and how to avoid the most common footguns. By the end, you'll be ready to refactor your next project for real performance wins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What Are React Server Components?&lt;/li&gt;
&lt;li&gt;The Fundamental Shift: Server-First Mental Model&lt;/li&gt;
&lt;li&gt;Practical Example: Building a Product Detail Page&lt;/li&gt;
&lt;li&gt;Visual Intuition: How the Data Flows&lt;/li&gt;
&lt;li&gt;Real-World Use Case: Dashboard with Streaming&lt;/li&gt;
&lt;li&gt;Advanced Tips: Composing Server + Client Components&lt;/li&gt;
&lt;li&gt;Common Mistakes &amp;amp; Gotchas&lt;/li&gt;
&lt;li&gt;Summary &amp;amp; Next Steps&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What Are React Server Components?
&lt;/h2&gt;

&lt;p&gt;React Server Components are components that **never **run on the client. They execute only on the server, can access databases, file systems, or secrets directly, and render to static HTML (or RSC payload) that's streamed to the browser.&lt;br&gt;
Key differences from classic "client" components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No hooks like &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt;(no interactivity by default)&lt;/li&gt;
&lt;li&gt;Zero client-side JS for these parts&lt;/li&gt;
&lt;li&gt;Can be async (await fetches right in the component)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;&lt;br&gt;
Server Components are the default in Next.js App Router. Just write your component — if you need client features, add &lt;code&gt;"use client";&lt;/code&gt; at the top.&lt;/p&gt;

&lt;p&gt;This shift means most of your UI can be server-rendered, slashing bundle sizes and improving Core Web Vitals.&lt;/p&gt;
&lt;h2&gt;
  
  
  Practical Example: Building a Product Detail Page
&lt;/h2&gt;

&lt;p&gt;tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// app/products/[id]/page.tsx
// This is a Server Component by default

import { getProduct } from '@/lib/api';
import AddToCartButton from './AddToCartButton'; // Client component

export default async function ProductPage({ params }: { params: { id: string } }) {
  const product = await getProduct(params.id); // Runs on server, can be DB query

  return (
    &amp;lt;div className="max-w-4xl mx-auto p-6"&amp;gt;
      &amp;lt;h1 className="text-3xl font-bold"&amp;gt;{product.name}&amp;lt;/h1&amp;gt;
      &amp;lt;p className="text-xl text-gray-600 mt-2"&amp;gt;${product.price}&amp;lt;/p&amp;gt;

      &amp;lt;img 
        src={product.image} 
        alt={product.name} 
        className="w-full h-96 object-cover rounded-lg mt-6"
      /&amp;gt;

      &amp;lt;div className="mt-8"&amp;gt;
        &amp;lt;h2 className="text-2xl font-semibold"&amp;gt;Description&amp;lt;/h2&amp;gt;
        &amp;lt;p className="mt-4"&amp;gt;{product.description}&amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;

      {/* Only this part needs interactivity */}
      &amp;lt;AddToCartButton productId={product.id} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// AddToCartButton.tsx
"use client";

import { useState } from 'react';

export default function AddToCartButton({ productId }: { productId: string }) {
  const [status, setStatus] = useState&amp;lt;'idle' | 'adding' | 'added'&amp;gt;('idle');

  const handleAdd = async () =&amp;gt; {
    setStatus('adding');
    // Simulate API call
    await new Promise(r =&amp;gt; setTimeout(r, 800));
    setStatus('added');
  };

  return (
    &amp;lt;button
      onClick={handleAdd}
      disabled={status === 'adding'}
      className="mt-6 px-8 py-4 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50 transition"
    &amp;gt;
      {status === 'adding' ? 'Adding...' : status === 'added' ? 'Added! 🎉' : 'Add to Cart'}
    &amp;lt;/button&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See? 90% of the page is server-rendered, zero JS for the static content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha!&lt;/strong&gt;&lt;br&gt;
You cannot pass functions or complex objects as props from Server to Client components only serializable data (strings, numbers, etc.).&lt;/p&gt;
&lt;h2&gt;
  
  
  Visual Intuition: How the Data Flows
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fep0iej3wl6az6bwomkhd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fep0iej3wl6az6bwomkhd.png" alt="When a user requests a page, the request goes to the Next.js server, where React components are rendered on the server. The server starts streaming HTML to the browser immediately instead of waiting for everything to finish. Along with the HTML, a React Server Components (RSC) payload is sent. The browser can display the page right away, and only small, necessary JavaScript files are loaded later to make interactive parts (islands) work." width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The magic is streaming: users see the product title and image first, then description fills in as data arrives no full-page loading spinner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-World Use Case: Dashboard with Streaming&lt;/strong&gt;&lt;br&gt;
In a real admin dashboard, you might have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Header (server)&lt;/li&gt;
&lt;li&gt;Sidebar with user data (server)&lt;/li&gt;
&lt;li&gt;Main content: charts loading slowly (streamed)&lt;/li&gt;
&lt;li&gt;Interactive filters (client island)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use &lt;code&gt;Suspense&lt;/code&gt;boundaries to stream sections independently:&lt;/p&gt;

&lt;p&gt;tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Suspense fallback={&amp;lt;Skeleton /&amp;gt;}&amp;gt;
  &amp;lt;SlowChart dataPromise={fetchAnalytics()} /&amp;gt;
&amp;lt;/Suspense&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is huge for perceived performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Tips: Composing Server + Client Components
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Nest Client inside Server: Fine!&lt;/li&gt;
&lt;li&gt;Nest Server inside Client: Not allowed (importing server component in      client throws error)&lt;/li&gt;
&lt;li&gt;Use Server Actions for mutations (form actions that run on server)&lt;/li&gt;
&lt;li&gt;Leverage async/await in components for clean data fetching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;&lt;br&gt;
Combine with React 19's useOptimistic for instant feedback on actions, then sync with server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes &amp;amp; Gotchas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Trying to use hooks in Server Components — instant error. Solution: Move to client.&lt;/li&gt;
&lt;li&gt;Passing non-serializable props — functions, Dates, etc. → stringify or convert.&lt;/li&gt;
&lt;li&gt;Forgetting Suspense — no streaming, worse UX.&lt;/li&gt;
&lt;li&gt;Overusing Client Components — ask: "Does this need state or effects?" If no, make it server.&lt;/li&gt;
&lt;li&gt;State leakage — never use global stores in server code (e.g., Zustand pitfalls).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
React Server Components represent the biggest architectural shift since Hooks. By defaulting to server rendering, streaming content, and minimizing client JS, you build apps that feel native fast even on 3G.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Further Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react.dev/reference/rsc?referrer=grok.com" rel="noopener noreferrer"&gt;React Server Components RFC (official docs)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nextjs.org/docs/app?referrer=grok.com" rel="noopener noreferrer"&gt;Next.js App Router Patterns for Data Fetching&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Personal takeaway:&lt;/strong&gt; Once you experience streaming + minimal JS, going back to full-client feels like time travel to 2018.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>react</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why Islands Architecture is the SSR Wake-Up Call Your React App Has Been Begging For🧑‍💻🚀</title>
      <dc:creator>Krish Carter</dc:creator>
      <pubDate>Mon, 01 Dec 2025 14:14:26 +0000</pubDate>
      <link>https://forem.com/krish_kakadiya_5f0eaf6342/why-islands-architecture-is-the-ssr-wake-up-call-your-react-app-has-been-begging-for-4n46</link>
      <guid>https://forem.com/krish_kakadiya_5f0eaf6342/why-islands-architecture-is-the-ssr-wake-up-call-your-react-app-has-been-begging-for-4n46</guid>
      <description>&lt;p&gt;&lt;strong&gt;Build lightning-fast, interactive UIs without the hydration headaches—discover how "islands" can slash your bundle sizes and boost user delight in real-world apps.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Table of Contents&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What Are "Islands," and Why Should You Care?&lt;/li&gt;
&lt;li&gt;The SSR Struggle: Why Full Hydration is Draining Your App&lt;/li&gt;
&lt;li&gt;Building Your First Island: A Hands-On React Example&lt;/li&gt;
&lt;li&gt;Visualizing the Magic: Islands in Action&lt;/li&gt;
&lt;li&gt;Real-World Use Case: Turbocharging an E-Commerce Dashboard&lt;/li&gt;
&lt;li&gt;Advanced Islands: Optimization and Edge Cases&lt;/li&gt;
&lt;li&gt;Common Pitfalls and How to Dodge Them&lt;/li&gt;
&lt;li&gt;Wrapping Up: Chart Your Course to Island Paradise&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Are "Islands," and Why Should You Care?
&lt;/h2&gt;

&lt;p&gt;Before we dive into the "how," let's unpack the "why." Traditional SSR in frameworks like Next.js renders your entire page on the server, ships HTML to the browser, and then hydrates it all with JavaScript to make it interactive. &lt;/p&gt;

&lt;p&gt;It's like watering your whole lawn to keep one flower alive efficient until it's not. Enter Islands Architecture: a pattern where most of your page stays static HTML (no JS overhead), but "islands" small, isolated components get selectively hydrated for interactivity. Think of it as planting sprinklers only where the grass actually grows.&lt;/p&gt;

&lt;p&gt;This isn't some ivory tower theory. Pioneered by folks at frameworks like Astro and Qwik, islands solve real pains: massive JS payloads, hydration mismatches, and zombie states where static content fights dynamic updates. In practice, it means your app loads in under 100ms, SEO thrives on static shells, and users get instant feedback where it counts like a search bar or carousel, not the footer links.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt;Islands shine in content-heavy sites (blogs, docs) or hybrid apps. If your page is 80% static, you're leaving performance on the table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility note:&lt;/strong&gt; Islands preserve semantic HTML for screen readers out of the box, since static parts don't rely on JS. Just ensure your hydrated islands emit ARIA compliant events.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SSR Struggle: Why Full Hydration is Draining Your App
&lt;/h2&gt;

&lt;p&gt;Full hydration sounds great on paper ship HTML, then "wake it up" with JS. But here's the rub: Your entire component tree re-runs on the client, even for non-interactive bits like a hero image or static nav. This leads to "hydration waterfalls": one slow component blocks the lot, inflating TTI (Time to Interactive) and frustrating users.&lt;br&gt;
Consider a typical Next.js page: A blog post with a comment form. You hydrate everything—the post body, sidebar ads, even the copyright notice just to enable comments. Result? 1.5MB JS for a 10KB interaction. No wonder 53% of mobile users abandon sites taking over 3 seconds to load (Google stats, anyone?).&lt;/p&gt;

&lt;p&gt;Islands fix this by defaulting to static rendering and opting in to hydration. It's declarative: Mark interactive zones explicitly, and the framework handles the rest. Why care? Faster loads = happier users = better metrics. In A/B tests I've run, island-ified pages saw 25% uplift in engagement. Your turn.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building Your First Island: A Hands-On React Example
&lt;/h2&gt;

&lt;p&gt;Enough theory let's build. We'll use Next.js 14+ with the experimental &lt;code&gt;dynamic&lt;/code&gt; API to create an island for a simple search component. Assume you've got a fresh Next.js app (&lt;code&gt;npx create-next-app@latest&lt;/code&gt;).&lt;br&gt;
First, set up your page in &lt;code&gt;app/page.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// app/page.tsx
import StaticContent from '@/components/StaticContent';
import SearchIsland from '@/components/SearchIsland';

export default function Home() {
  return (
    &amp;lt;main&amp;gt;
      &amp;lt;StaticContent /&amp;gt;
      &amp;lt;SearchIsland /&amp;gt;
    &amp;lt;/main&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the static part (&lt;code&gt;components/StaticContent.tsx&lt;/code&gt;): Pure HTML, no JS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// components/StaticContent.tsx
export default function StaticContent() {
  return (
    &amp;lt;section&amp;gt;
      &amp;lt;h1&amp;gt;Welcome to Island Paradise&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;This static bliss loads instantly—no hydration needed.&amp;lt;/p&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;Fast first paint&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;SEO-friendly&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;Zero JS bloat&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/section&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter the island (&lt;code&gt;components/SearchIsland.tsx&lt;/code&gt;): This gets hydrated client-side only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// components/SearchIsland.tsx
'use client'; // Marks this as client-only island

import { useState } from 'react';

interface SearchIslandProps {
  initialResults: string[];
}

export default function SearchIsland({ initialResults }: SearchIslandProps) {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState(initialResults);

  const handleSearch = (e: React.ChangeEvent&amp;lt;HTMLInputElement&amp;gt;) =&amp;gt; {
    const value = e.target.value;
    setQuery(value);
    // Simulate API call
    setResults(initialResults.filter(item =&amp;gt; item.includes(value)));
  };

  return (
    &amp;lt;div role="search" aria-label="Site search"&amp;gt;
      &amp;lt;input
        type="search"
        value={query}
        onChange={handleSearch}
        placeholder="Search islands..."
        aria-autocomplete="list"
      /&amp;gt;
      &amp;lt;ul aria-live="polite"&amp;gt;
        {results.map((result, idx) =&amp;gt; (
          &amp;lt;li key={idx}&amp;gt;{result}&amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pass static props from the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// In page.tsx, add:
&amp;lt;SearchIsland initialResults={['React Island', 'SSR Lagoon', 'Hydration Cove']} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;npm run dev&lt;/code&gt; watch the magic. The page paints instantly, then the search input "wakes up" without re-rendering the static content. Boom: Selective hydration achieved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:-&lt;/strong&gt; Forgetting &lt;code&gt;'use client'&lt;/code&gt; turns your island into a static rock. Always mark interactive components explicitly to avoid mismatches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing the Magic: Islands in Action
&lt;/h2&gt;

&lt;p&gt;Imagine your app as an archipelago. The ocean? Static HTML, calm and quick. Each island? A hydrated hotspot, buzzing with life. Tools like React DevTools show this: Static nodes are inert; islands light up with state.&lt;/p&gt;

&lt;p&gt;Visually, it's like progressive enhancement on steroids. Users see content now, interact soon. Intuition: Hydration isn't a flood it's targeted rain. This mental model prevents over-engineering: Ask, "Does this need JS?" 90% of the time, no.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Case: Turbocharging an E-Commerce Dashboard
&lt;/h2&gt;

&lt;p&gt;Let's scale it. You're building a dashboard for an online store product grids (mostly static), filters (interactive), and a cart widget (dynamic). Full SSR? Grid hydrates pointlessly, slowing everything.&lt;/p&gt;

&lt;p&gt;Refactor: Make the grid an island for lazy-loaded images, filters a full island, cart another. In Next.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// app/dashboard/page.tsx
import ProductGrid from '@/components/ProductGrid'; // Static
import FiltersIsland from '@/components/FiltersIsland'; // Hydrated
import CartIsland from '@/components/CartIsland'; // Hydrated

export default async function Dashboard() {
  const products = await fetchProducts(); // Server fetch

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;ProductGrid products={products} /&amp;gt;
      &amp;lt;FiltersIsland initialFilters={defaultFilters} /&amp;gt;
      &amp;lt;CartIsland /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ProductGrid.tsx&lt;/code&gt; stays static: Loop over props, render &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; with images. Filters and Cart get &lt;code&gt;'use client'&lt;/code&gt; for state. Result? Dashboard loads in 800ms vs. 3s, with filters responding in 50ms. In my last project, this cut cart abandonment by 15% users felt the speed.&lt;/p&gt;

&lt;p&gt;**Accessibility win: **Static grids work offline and with JS disabled, falling back gracefully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; Use Suspense boundaries around islands for streaming: }&amp;gt;. It's like async loading your treasures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Islands: Optimization and Edge Cases
&lt;/h2&gt;

&lt;p&gt;You've got the basics now level up. For shared state across islands? Libraries like Zustand (lightweight) or signals in Qwik prevent prop-drilling hell. Bundle splitting? Webpack's magicModules auto chunks islands.&lt;br&gt;
Edge case: Nested islands. Avoid deep nesting flatten for perf. In React, use &lt;code&gt;dynamic&lt;/code&gt; imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import dynamic from 'next/dynamic';
const NestedWidget = dynamic(() =&amp;gt; import('@/components/Widget'), { ssr: false });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Measure with Lighthouse: Aim for 90+ perf scores. Pro move: Pre-hydrate critical islands via &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags for sub-100ms interactivity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Pitfalls and How to Dodge Them&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1.Over-islanding: Not everything needs hydration keep islands &amp;lt;10% of your tree. Dodge: Audit with why did you render.&lt;br&gt;
2.Hydration mismatches from timestamps/dates. Fix: Render dates server side with toISOString().&lt;br&gt;
3.SEO woes if islands hold key content. Solution: Prerender dynamic props.&lt;/p&gt;

&lt;p&gt;Don't turn your app into the Bermuda Triangle test islands in dev/prod to avoid vanishing interactions.&lt;/p&gt;

</description>
      <category>astro</category>
      <category>react</category>
      <category>webdev</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
