Skip to content
GeeksSmith
advanced 10 min read

Frontend System Design (HLD) Framework for Production Projects

A standardized 7-step architectural blueprint to systematically structure, articulate, and defend any complex frontend production system in Senior/Lead/Staff technical interviews.

Why it matters in interviews

Asked across Tekion Corp Round 2 ('Discuss HLD of your current/past frontend system covering modules, component hierarchy, API contracts, caching, performance, response time & availability'), Google, Uber, and Amazon. Interviewers assess architectural ownership, trade-off clarity, and operational scalability.

Visual & Interactive Explanation

Interactive Flow Execution

Code Examples & Implementation

Frontend HLD System Architecture Template (Interview Walkthrough)
/**
 * PRODUCTION FRONTEND ARCHITECTURE BLUEPRINT
 * 
 * 1. MODULE BOUNDARIES:
 *    - Shell / Host: Authentication, Navigation, Dynamic Theming, Notification Toast Hub
 *    - Feature Pods: Independent domain packages (@app/analytics, @app/inventory, @app/checkout)
 *    - Shared UI Core: Headless design system primitives, formatting utilities, API clients
 * 
 * 2. COMPONENT HIERARCHY:
 *    <AppShell>
 *      <GlobalErrorBoundary>
 *        <QueryClientProvider>
 *          <HeaderNavigation />
 *          <Suspense fallback={<PageSkeleton />}>
 *            <FeatureContainer>
 *              <WidgetGrid>
 *                <WidgetBoundary name="ChartWidget">
 *                  <VirtualizedDataGrid />
 *                </WidgetBoundary>
 *              </WidgetGrid>
 *            </FeatureContainer>
 *          </Suspense>
 *        </QueryClientProvider>
 *      </GlobalErrorBoundary>
 *    </AppShell>
 * 
 * 3. STATE TAXONOMY:
 *    - Server Cache: TanStack Query (staleTime: 60s, cacheTime: 5m, retry: 3)
 *    - Navigation State: URL query params (?filter=active&page=2) (Single source of truth)
 *    - Ephemeral UI State: Local useState / useReducer (Modal open, hover tooltip)
 *    - Offline Store: IndexedDB via idb-keyval (Draft form mutations)
 */
Resilient API Client with Deduplication & Offline Retry Queue
import { TaskScheduler } from "./scheduler";

export class ResilientApiClient {
  private inFlightRequests = new Map<string, Promise<any>>();
  private scheduler = new TaskScheduler(6); // Max 6 concurrent HTTP/2 streams

  async request<T>(url: string, options: RequestInit = {}): Promise<T> {
    const method = options.method || "GET";
    const cacheKey = `${method}:${url}:${JSON.stringify(options.body || {})}`;

    // 1. Request Deduplication for concurrent GETs
    if (method === "GET" && this.inFlightRequests.has(cacheKey)) {
      return this.inFlightRequests.get(cacheKey)!;
    }

    const promise = this.scheduler.add(async () => {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 10000); // 10s deadline

      try {
        const response = await fetch(url, { ...options, signal: controller.signal });
        clearTimeout(timeoutId);

        if (!response.ok) {
          throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        return await response.json();
      } finally {
        this.inFlightRequests.delete(cacheKey);
      }
    });

    if (method === "GET") {
      this.inFlightRequests.set(cacheKey, promise);
    }

    return promise;
  }
}

Interview-Ready Answers

Structure any frontend HLD into 7 layers: Scope/Scale, Module Boundaries, Component Hierarchy, API Contracts, Multi-Tier Caching, Performance Optimizations, and NFRs (Availability, Latency, Observability).

Follow-up Questions & Deep Dives

🎯 Code Output — What Does This Print?

Question 1medium
// What is the primary advantage of navigator.sendBeacon over fetch?
// A: It supports HTTP PUT and DELETE
// B: It is guaranteed to send even if the user closes the tab immediately
// C: It bypasses CORS preflight checks for all requests
// D: It runs in a separate Web Worker thread

Common Mistakes & Anti-Patterns

  • Dumping all API responses into global Redux store without cache invalidation or TTL policies
  • Not mentioning localized Error Boundaries for widget isolation
  • Ignoring mobile networks (relying on high-bandwidth desktop Wi-Fi assumptions)
  • Failing to articulate clear Non-Functional Requirements (NFRs) like INP, LCP, and availability metrics

Implementation Evolution: Anti-Pattern to Production

❌ Anti-Pattern: Monolithic Global State & Missing Fault Isolation

// ❌ Anti-Pattern: Putting ALL server data into a single Redux store without error boundaries
function BigDashboard() {
  // If ANY widget fails to load data or throws during render, the ENTIRE dashboard crashes!
  return (
    <div>
      <WidgetA />
      <WidgetB />
      <WidgetC />
    </div>
  );
}
Why this breaks: Lacking localized Error Boundaries means an uncaught TypeError in Widget C unmounts the entire application, violating the 99.99% availability requirement.

✅ Correct Pattern: Granular Widget Boundaries & Server-State Segregation

// ✅ Correct: Isolated Error Boundaries with retry fallbacks and independent query hooks
function ResilientDashboard() {
  return (
    <div className="grid grid-cols-3 gap-4">
      <WidgetBoundary fallbackTitle="Sales Analytics">
        <Suspense fallback={<WidgetSkeleton />}>
          <SalesWidget />
        </Suspense>
      </WidgetBoundary>

      <WidgetBoundary fallbackTitle="Inventory Health">
        <Suspense fallback={<WidgetSkeleton />}>
          <InventoryWidget />
        </Suspense>
      </WidgetBoundary>
    </div>
  );
}
🚀

🚀 Production-Grade (Hardened): Real User Monitoring (RUM) & Performance Telemetry Beacon

// 🚀 Production: Automated Core Web Vitals & Error Telemetry Pipeline
export function initializeFrontendTelemetry() {
  // 1. Report unhandled Promise rejections and runtime errors
  window.addEventListener("error", (event) => {
    reportTelemetry("error", {
      message: event.message,
      stack: event.error?.stack,
      url: window.location.href,
      timestamp: Date.now(),
    });
  });

  window.addEventListener("unhandledrejection", (event) => {
    reportTelemetry("unhandled_rejection", {
      reason: String(event.reason),
      timestamp: Date.now(),
    });
  });
}

function reportTelemetry(type: string, payload: Record<string, any>) {
  const body = JSON.stringify({ type, payload });
  if (navigator.sendBeacon) {
    navigator.sendBeacon("/api/telemetry", body);
  } else {
    fetch("/api/telemetry", { method: "POST", body, keepalive: true }).catch(() => {});
  }
}

⚠️ Trick Questions & Interviewer Traps

Q1:How do you guarantee 99.99% frontend availability if backend microservices experience intermittent 500 errors?

Q2:Why is `navigator.sendBeacon` preferred over `fetch()` for error/analytics logging?

📋 Rapid Revision Cheat Sheet

  • Step 1: Scale & Constraints (DAU, mobile vs desktop, bandwidth limits).
  • Step 2: Module Boundaries (BFF, Micro-Frontends vs Modular Monorepo).
  • Step 3: Component Tree (Smart Containers -> Dumb Pure Primitives).
  • Step 4: State Taxonomy (Server Cache vs URL State vs Local Ephemeral).
  • Step 5: Multi-Tier Cache (Edge CDN -> Service Worker -> TanStack Query).
  • Step 6: Performance (Code Splitting, 2D Virtualization, Brotli, AVIF).
  • Step 7: NFRs (LCP < 1.8s, INP < 100ms, 99.99% Availability, sendBeacon RUM).

Real-World Architectural Scenario

The interviewer asks: 'Design the high-level frontend architecture for our high-throughput enterprise dashboard with 50 live widgets.' How do you answer in 5 minutes?

Rate Your Readiness

Rate how comfortably you can explain this in an interview to update your global readiness gauge:

Rate your confidence: