Skip to main content

3 posts tagged with "react"

View All Tags

Performant and Defensive Feature Flags in Next.js: A Full-Stack Architect’s Guide

· 6 min read
D Balaji
Lead Design Technologist

In modern software engineering, feature flags (toggles) are no longer optional; they are foundational primitives for Continuous Deployment, Trunk-Based Development, and Risk Mitigation. They allow us to decouple code deployment from feature release, enabling canary rollouts, A/B testing, and instant kill-switches.

However, in a Next.js environment—where rendering strategies are fragmented across Static (SSG), Server (SSR), and Client (CSR)—a naive feature flag implementation is dangerous. It leads to Cumulative Layout Shift (CLS), jarring user "flicker," performance bottlenecks, and security vulnerabilities.

As architects, we must move beyond simple if/else statements. This guide outlines a high-performance, defensive architecture for feature flags that works harmoniously across all Next.js rendering strategies.

We will use a running example: rolling out a new UPI (Unified Payments Interface) section within a payment form, controlled by the flag FF_SHOULD_SHOW_UPI_SECTION.


The Architectural Challenge: Performance vs. Security

A robust feature flag system must solve three problems simultaneously:

  1. Zero-Flicker Performance: Flags must be available before the first paint on the client to prevent hydration mismatch and CLS.
  2. Unification: Flag state must be consistent across Server Components (RSC) and Client Components (interactive elements).
  3. Defensive Security: The backend must treat the client UI state as "untrusted."

The Anti-Pattern: Client-Side Fetching (useEffect)

Fetching flags inside a useEffect after the component mounts creates a "race condition" between your UI rendering and your data loading. This results in content jumping and a poor LCP (Largest Contentful Paint).


Pillar 1: High-Performance Delivery (The Edge Pattern)

To achieve zero latency on the client, we must leverage the Next.js server layers to Bootstrap the flag data.

For the fastest global delivery, flags should be evaluated at the Edge. We use Next.js Middleware to intercept incoming requests, evaluate flags against user context (e.g., from a JWT), and pass the state down via cookies.

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getFlagsFromEdgeKV } from '@/lib/flag-provider';

export async function middleware(req: NextRequest) {
const userId = req.cookies.get('session')?.value;

// Fast evaluation at the edge (e.g., targeting 10% rollout)
const flags = await getFlagsFromEdgeKV(userId);

const res = NextResponse.next();

// Inject evaluated state into a cookie for the application logic
res.cookies.set('x-feature-flags', JSON.stringify(flags), {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
return res;
}


Pillar 2: Implementation Across Rendering Strategies

Now that flags are available via a cookie, we can consume them synchronously in both worlds of Next.js.

2.1 Consuming Flags in Server Components (RSC)

RSCs can read the cookie directly. This is the cleanest pattern, as no feature flag logic ever leaks to the client JavaScript bundle.

// app/checkout/PaymentSection.tsx (Server Component)
import { cookies } from 'next/headers';
import UPICard from './UPICard';

export default async function PaymentSection() {
const cookieStore = cookies();
const flagCookie = cookieStore.get('x-feature-flags')?.value;
const flags = flagCookie ? JSON.parse(flagCookie) : {};

const isUpiEnabled = flags.FF_SHOULD_SHOW_UPI_SECTION ?? false;

return (
<section>
<CreditCardForm />
{/* Rendered on server, zero client-side flicker */}
{isUpiEnabled && <UPICard />}
</section>
);
}

2.2 Consuming Flags in Client Components (Hydration Pattern)

For interactive elements that require Client Components, we use a Context Provider to synchronize server state with client hydration.

// providers/FeatureFlagProvider.tsx ('use client')
import { createContext, useContext, ReactNode } from 'react';

const FlagContext = createContext<Record<string, boolean>>({});

export function FeatureFlagProvider({ children, initialFlags }: { children: ReactNode, initialFlags: Record<string, boolean> }) {
return (
<FlagContext.Provider value={initialFlags}>
{children}
</FlagContext.Provider>
);
}

export const useFeatureFlag = (name: string) => useContext(FlagContext)[name] ?? false;


Pillar 3: Defensive Engineering & Backend Verification

Never trust the client UI. A user can use DevTools to modify the React context or manually unhide a hidden DOM element.

3.1 The "Double-Gate" Pattern

Verify the flag at the Action level (Server Action or API Route), regardless of what the UI showed.

// app/actions/process-payment.ts
'use server';

import { cookies } from 'next/headers';
import { getFlagsFromSource } from '@/lib/flag-service';

export async function processPayment(formData: FormData) {
const paymentMethod = formData.get('method');

const flagsCookie = cookies().get('x-feature-flags')?.value;
const flags = flagsCookie ? JSON.parse(flagsCookie) : {};

// 🛡️ SECURITY CHECK: Defensive gate
if (paymentMethod === 'UPI' && !flags.FF_SHOULD_SHOW_UPI_SECTION) {
console.error('Tampering detected: UPI submitted while flag is disabled.');
throw new Error("Unauthorized operation.");
}

// Proceed securely...
}


Pillar 4: Testing Suite (The Quality Lock)

4.1 Unit Testing (Vitest/Jest)

Unit tests focus on the immediate UI response by mocking our custom hook.

// __tests__/PaymentForm.test.tsx
import { render, screen } from '@testing-library/react';
import PaymentForm from '@/components/PaymentForm';
import { useFeatureFlag } from '@/hooks/useFeatureFlag';
import { vi, describe, it, expect } from 'vitest';

vi.mock('@/hooks/useFeatureFlag');

describe('PaymentForm Feature Toggling', () => {
it('should not render UPI section when flag is disabled', () => {
vi.mocked(useFeatureFlag).mockReturnValue(false);
render(<PaymentForm />);
expect(screen.queryByText(/Pay via UPI/i)).not.toBeInTheDocument();
});

it('should render UPI section when flag is enabled', () => {
vi.mocked(useFeatureFlag).mockReturnValue(true);
render(<PaymentForm />);
expect(screen.getByText(/Pay via UPI/i)).toBeInTheDocument();
});
});

4.2 E2E and Integration Testing (Playwright)

// e2e/feature-flags.spec.ts
import { test, expect } from '@playwright/test';

test('Standard User: Should NOT see UPI and API should reject tampering', async ({ page, context }) => {
await context.addCookies([{
name: 'x-feature-flags',
value: JSON.stringify({ FF_SHOULD_SHOW_UPI_SECTION: false }),
domain: 'localhost',
path: '/'
}]);

await page.goto('/checkout');
await expect(page.getByText('Pay via UPI')).toBeHidden();

// ADVERSARIAL TEST: Force a UPI submission via fetch
const responseStatus = await page.evaluate(async () => {
const formData = new FormData();
formData.append('method', 'UPI');
const res = await fetch('/checkout', { method: 'POST', body: formData });
return res.status;
});

expect(responseStatus).toBe(403);
});


Pillar 5: Flag Retirement (The Cleanup)

Feature flags are Technical Debt with an expiration date. Once a feature is 100% rolled out, use this AI prompt to clean your codebase surgically.

The Architect's Cleanup Prompt

Role: Senior Frontend Architect. Task: Remove the feature flag FF_SHOULD_SHOW_UPI_SECTION and promote the "True" state as permanent. Guidelines: > 1. Find all conditional blocks dependent on this flag and keep only the "true" path. 2. Delete useFeatureFlag hook calls and associated variables. 3. Remove the security check in Server Actions that validates if the flag is enabled. 4. Delete unit tests that assert "should not render when flag is false." 5. Clean up unused imports.


Conclusion

By leveraging Middleware, Server Components, and defensive backend checks, we ensure our Next.js apps are fast, secure, and ready for rapid iteration. Feature flags should empower your team, not burden your architecture.

React Nexus 2025 in 25 Points

· 3 min read
D Balaji
Lead Design Technologist

React Nexus 2025: React Harder

Second time at React Nexus. Bigger venue, bigger sponsors, same old dev jokes. Held at Tata Auditorium, IISC – beautiful place if you like trees and long walks to the nearest metro.

What Went Down (Other Than My Battery)

  • Logistics: One sticker. One tee. One meal per day. That’s the deal. Cab-friendly, metro-unfriendly.

  • Sponsors: Took the stage like Bollywood villains. Some reruns from 2024. Gemini & Copilot aced the quizzes more than the attendees did.

  • ImageKit.io: Indie builder CEO handing out stickers = 🫶 Who knew images + GenAI + AWS could be a profitable cocktail?

  • GoDaddy: Still selling domains like flash sales. Bought one. Page still says “Hello World.” Now with GenAI, they add the hello page for you. Still pushing Outlook 365 like it’s going out of stock.

  • Vonage: Zoom-ish APIs. Most colorful booth. Least understood by crowd. They were hiring.

  • WSO2 Asgardeo: Auth-as-a-service. Repeat speaker, repeat stickers. Still no buy-in from bosses.

  • Zoho Catalyst: “Run everything with us (on free tier).” Indie energy, real. Good for side projects, enterprise signup after sales men raids. Might convert prompt to SaaS if you squint hard enough.

  • Code of Conduct Slide: The usual “don’t harass women” clause. But honestly, dev conferences now look like HR onboarding. 50/50 gender ratio. Welcome change.

  • React 19 + NextJS: Headliners. React Actions API opened the show. Time to un-dust the docs.

  • Audience Engagement: Peak Bangalore moment: guy hacked, built, and launched a product on New Year’s Eve. 🙌

  • React Compiler: Still a mystery box. Used in 3D video gen demo—hit and miss.

  • Best Speaker? Wadad Parker. Tackled React Context with stand-up energy. Put Toastmasters to shame.

  • GoDaddy Talk on Microfrontends: Enlightening. But no tools, just “vibes.”

  • Tech Company vs Software Company vs Vibe-Coded Startup:

    • Tech company = builds tech
    • Software company = builds from packages
    • Vibe-coded = builds vibes, nothing else
  • Zoho Catalyst (again): Their domain setup is easier than your weekend plans.

  • Lighthouse Talk (again): Same speaker. Same slides. Different year. Look at web.dev if you need filler content, apparently.

  • Monitoring & Observability: Not the same. One alerts, one explains. Both are friends now.

  • Frontend QA: Smoke tests > Nothing. Playwright > Hope. Monitoring > Late-night debugging.

  • Telemetry 101: Metrics, logs, traces... add them to your design system if you want to sound senior.

  • AI Tools: Cursor’s @web, @docs, @diff = DevGPT mode unlocked.

  • MCP (Magic Component Platform): Figma → Code without tears. Everyone's happy. Until you self-host it online and leak your keys.

  • React Dev Joke Moment: “Lazy loading is like buying 10 chips, eating one at a time.” Me: “Bro that’s throttling. Lazy loading = frequent runs to the shop.”

  • React Native: Few talks. Fewer fans. Still exists.

  • Browser-LLMs: Local LLMs in your browser soon. Because why not.


Conclusion: React is evolving, audiences are engaging, and conferences are quietly becoming better. React Nexus 2025 felt more like a community summit than a sponsor expo—despite the sponsor overload. Chennai devs showed up in droves. Peaceful vibes. Good chai. No one shipped to production from the venue, which is a win.

P.S. I still haven’t deployed that domain I bought.

Docusaurus - in <p/> * 3

· One min read
D Balaji
Lead Design Technologist

What is Docusaurus

A react based static site generator which is modern and developed at facebook. Has rss generator, dark theme, navbar and other important parts of a website built in. Ideal for documentation websites and blogs. Has no support for backend integration.

Most useful parts

Docusaurus has 3 important parts

  • documents - useful to show online handbooks
  • blog - chronological sequence of articles
  • pages - standalone parts of the website

The hard parts

  • Too many options for authoring content. md, mdx & react.
  • preset classic has lot of bundled plugins, afraid of stepping out of classic preset.
  • swizzle themes to modify react components of the website.