TL;DR
- Strong frontend system design answers start by narrowing scope, not by drawing boxes too early.
- I evaluate the full stack: browser, service worker, CDN, BFF, backend APIs, and observability.
- The recurring trade-offs are SSR vs CSR vs RSC, cache freshness vs speed, and independence vs consistency in multi-team UI systems.
- At principal level, I expect the discussion to include failure modes, metrics, and organizational boundaries, not just framework choices.
Context
Frontend system design interviews are rarely about a component tree. They are about how the browser, CDN, BFF, rendering model, and backend contracts work together under product constraints. This is especially relevant in the kind of systems I have worked around: large React and Next.js applications with shared UI infrastructure, experimentation, multiple downstream services, and heavy performance expectations.
The Approach
1. Scope the prompt before solving it
If someone says “design Twitter” or “design a collaborative editor,” I narrow it first:
- which client? mobile web, desktop web, or native wrapper?
- read-heavy or write-heavy path?
- authenticated or SEO-sensitive?
- real-time or eventual consistency?
- what scale actually matters?
That turns a vague question into an architecture problem I can reason about.
2. Work the stack top to bottom
The layers I usually cover:
- browser: memory, storage, hydration, responsiveness
- edge/CDN: static assets, image optimization, edge routing
- BFF: aggregation, auth-aware shaping, SSR/RSC decisions
- backend: REST, GraphQL, gRPC, event-driven dependencies
- observability: RUM, trace correlation, error tagging, performance budgets
3. Choose rendering strategy explicitly
My rendering decision matrix usually looks like this:
- CSR for authenticated, interaction-heavy apps where SEO is irrelevant
- SSR when initial content speed or crawlability matters
- SSG/ISR for docs, marketing, or content with relaxed freshness
- RSC when I want server-owned data composition with lower client JS cost
The important point is not to recite the matrix. It is to explain why a route or feature earns one strategy over another.
4. Treat the BFF as a serious design layer
I like a backend-for-frontend when the page needs:
- fan-out to many downstream services
- auth/session-aware shaping
- device-specific response shaping
- fewer client round trips
I keep orchestration in the BFF, but I avoid putting durable business rules there. Otherwise the BFF turns into a second product backend.
5. Cache at multiple layers with explicit invalidation
I want the design conversation to include:
- browser memory and client cache
- service worker / Cache API
- HTTP cache headers
- CDN cache
- BFF in-memory or request cache
The real question is not “should we cache?” It is:
- what is the TTL?
- what invalidates it?
- can I serve stale?
- what happens on cache miss?
6. Real-time is a transport choice and a product choice
I choose transport by directionality and latency:
- SSE for server-to-client streams like notifications or AI output
- WebSocket for bidirectional chat or collaboration
- long polling as a compatibility fallback
- WebRTC only when peer-to-peer media or low-latency peer channels really matter
7. Micro-frontends are an organizational decision first
When the design prompt touches multi-team UI ownership, I discuss:
- route-level vs component-level boundaries
- shell responsibilities
- shared design system and auth
- remote failure isolation
- versioning and observability
I only recommend micro-frontends when deployment independence and team autonomy clearly outweigh the runtime complexity.
Trade-offs
- Richer BFF and edge layers improve UX and latency, but they also create more places where logic can drift.
- SSR and RSC improve first content speed, but they increase server responsibility and debugging complexity.
- Heavy caching improves performance, but stale data and invalidation bugs become product issues quickly.
- Micro-frontends can scale organizations well, but they can fragment performance budgets and UX consistency if the platform is weak.