Frontend System Design
The RADIO Framework for Frontend System Design
Frontend system design interviews test a completely different skill set than backend system design. While backend focuses on databases, load balancers, and distributed systems, frontend system design focuses on component architecture, state management, rendering performance, and user experience.
How Frontend Differs from Backend System Design
| Aspect | Backend System Design | Frontend System Design |
|---|---|---|
| Focus | Scalability, storage, throughput | Responsiveness, rendering, UX |
| State | Database, cache, message queues | Component state, URL, local storage |
| Network | Service-to-service communication | API calls, real-time connections |
| Failure | Server crashes, network partitions | Offline mode, slow connections |
| Scale | Millions of requests/second | 60fps rendering, bundle size |
The RADIO Framework
RADIO gives you a repeatable structure for any frontend system design question. Walk through each step in order:
R - Requirements → Clarify scope and constraints
A - Architecture → Component tree and page layout
D - Data Model → State shape, where it lives, how it flows
I - Interface → API contracts between components and server
O - Optimization → Performance, accessibility, edge cases
Step 1: Requirements
Spend the first 3-5 minutes asking clarifying questions. Split requirements into functional and non-functional:
Functional requirements (what it does):
- What are the core user actions?
- What data is displayed?
- What interactions are supported?
Non-functional requirements (how well it does it):
- How many concurrent users?
- What devices and browsers must be supported?
- What latency targets? (e.g., search results under 200ms)
- Offline support needed?
- Accessibility requirements (WCAG level)?
Step 2: Architecture
Sketch the component tree. Start with the page-level layout, then drill into each section:
<App>
├── <Header>
│ ├── <Logo />
│ ├── <SearchBar />
│ └── <UserMenu />
├── <Sidebar>
│ └── <Navigation />
└── <MainContent>
├── <FilterPanel />
└── <ResultsList>
└── <ResultCard /> (repeated)
Key decisions to explain:
- Which components are smart (stateful) vs. dumb (presentational)?
- Where do you split the component boundary?
- Which components are lazy-loaded?
Step 3: Data Model
Define the state shape and where each piece of state lives:
// Server state (fetched, cached via TanStack Query or SWR)
interface ServerState {
products: Product[];
userProfile: User;
notifications: Notification[];
}
// Client state (local to the UI)
interface ClientState {
searchQuery: string;
selectedFilters: Filter[];
isModalOpen: boolean;
currentPage: number;
}
// URL state (shareable, bookmarkable)
interface URLState {
category: string; // /products?category=electronics
sortBy: string; // /products?sort=price-asc
page: number; // /products?page=3
}
State management decision tree:
| State Type | Where It Lives | Tool |
|---|---|---|
| Server data | Cache layer | TanStack Query, SWR |
| Global UI state | External store | Zustand, Redux Toolkit |
| Local UI state | Component | useState, useReducer |
| URL-dependent | URL params | useSearchParams, router |
| Form data | Form library | React Hook Form, Formik |
Step 4: Interface (API Layer)
Define the contracts between your frontend and the server:
// REST API design
GET /api/products?q=laptop&category=electronics&page=1&limit=20
POST /api/products // create
PATCH /api/products/:id // partial update
DELETE /api/products/:id // delete
// Response shape
interface APIResponse<T> {
data: T;
pagination: {
page: number;
totalPages: number;
totalItems: number;
};
error?: { code: string; message: string };
}
REST vs. GraphQL decision:
| Factor | REST | GraphQL |
|---|---|---|
| Multiple resources | Multiple round trips | Single query |
| Overfetching | Returns full objects | Request exact fields |
| Caching | HTTP cache-friendly | Needs normalized cache |
| Team setup | Simpler to start | Needs schema + tooling |
Real-time updates strategy:
| Method | Use When | Overhead |
|---|---|---|
| Polling | Low-frequency updates (every 30s+) | Low complexity |
| SSE | Server pushes events one-way (notifications, feeds) | Medium |
| WebSocket | Bidirectional real-time (chat, collaboration) | Highest |
Step 5: Optimization
This is where you differentiate yourself. Cover:
Rendering performance:
- Virtualized lists for long scrolling content (react-window, TanStack Virtual)
- Code splitting with
React.lazy()and route-based chunking - Optimistic updates for perceived speed
Network performance:
- Request deduplication and caching
- Prefetching on hover or route proximity
- Image optimization (lazy loading, srcset, WebP/AVIF)
Accessibility:
- Keyboard navigation for all interactive elements
- ARIA attributes for custom widgets
- Focus management on route changes
Edge cases:
- Offline mode with service worker caching
- Error boundaries for graceful failure
- Empty states, loading states, error states
Practical Example: RADIO Applied to a Search Page
Let us walk through RADIO for a product search page:
R (Requirements): Users search products by keyword, filter by category and price, sort results, paginate through them. Must work on mobile. Target: results in under 200ms.
A (Architecture):
<SearchPage>
├── <SearchBar /> // debounced input
├── <ActiveFilters /> // chips showing current filters
├── <FilterSidebar /> // category, price range
└── <ResultsPanel>
├── <SortControls /> // relevance, price, rating
├── <ProductGrid>
│ └── <ProductCard /> (repeated)
└── <Pagination />
D (Data Model): Search query and filters live in URL params (shareable). Products are server state cached by TanStack Query with the query string as cache key.
I (Interface): GET /api/search?q=laptop&category=electronics&minPrice=500&sort=price-asc&page=1 returns paginated results with facet counts.
O (Optimization): Debounce search input by 300ms. Prefetch next page. Virtualize product grid on mobile. Use <img loading="lazy">. Add aria-live="polite" region for screen reader announcements when results update.
Interview tip: Always draw the component tree and state flow on the whiteboard. Interviewers want to see your thought process, not just hear it.
Next, we will walk through three classic frontend system design problems step by step. :::