If You Remember One Thing
In a system design interview, your data model is the contract for everything else: rendering strategy, UI states, caching, and reliability. If your entities, ownership boundaries, and invalidation rules are explicit, your frontend system design answer sounds senior and survives follow-up questions.
In the RADIO framework, Data model is where scope and architecture become concrete contracts.
What Data Model Must Produce
| Artifact | Minimum interview output | Why it matters |
|---|---|---|
| Entity map | Core entities, IDs, and relations | Prevents hand-wavy domain modeling |
| State ownership table | Server truth vs client UI state vs URL state | Avoids sync bugs and duplicate sources of truth |
| UI states matrix | idle/loading/success/empty/error/stale/partial | Shows production-ready frontend thinking |
| Cache policy | Query keys, TTLs, and invalidation triggers | Makes stale behavior predictable |
| Mutation flow | Optimistic update, rollback, and conflict handling | Tests write-path maturity |
Inputs You Must Carry from Requirements and Architecture
Data model quality is a dependency chain. Good system design interview preparation means carrying constraints forward, not resetting at each step.
| Input | Data-model decision | What to say out loud |
|---|---|---|
| Primary user flow | Model entities around top task first | "I am modeling the highest-value user path before edge entities." |
| Route rendering split | Separate SSR-safe payloads from CSR-interactive state | "I am designing data contracts to support both SSR payload and CSR updates." |
| Scale and latency targets | Define pagination shape, cache key granularity, and TTL | "I will tune key and TTL design to hit p95 latency targets." |
| Reliability requirements | Add stale and partial states in contracts | "I will include stale and partial response semantics in the model." |
| Security constraints | Model field visibility by role/scope | "I am separating public and privileged fields at contract level." |
Entity Model and API Contracts
Entity sketch template
Suggestion {
id: string
label: string
type: 'user' | 'repo' | 'doc'
score?: number
updatedAt: string
}
SearchResponse {
query: string
items: Suggestion[]
nextCursor?: string
stale: boolean
partial: boolean
}Modeling rules you should state
- Every entity has stable ID and update timestamp/version.
- Keep payloads route-focused; avoid over-fetching fields not rendered.
- Represent optional capability as explicit fields, not implicit null behavior.
- Include metadata needed for UI state decisions (for example,
stale,partial).
API data contracts for frontend system design
A strong frontend API contracts interview answer explains not only the endpoint shape, but also how the contract drives UI states, cache keys, pagination, realtime updates, and failure recovery.
| Contract style | Use when | Frontend data-model decision | Risk to call out |
|---|---|---|---|
| REST resource endpoints | Entities and list/detail screens are stable | Stable IDs, cursor shape, field visibility, HTTP cache headers | Over-fetching or inconsistent error shape across endpoints |
| GraphQL query shape | Views need flexible fields across related entities | Normalized cache keys, fragments, nullability, permission-safe fields | Hidden N+1 cost and fragile client assumptions about optional fields |
| WebSocket / SSE stream | Freshness changes the experience | Event schema, ordering token, dedupe key, reconnect and replay rules | Out-of-order events and memory growth from unbounded streams |
| BFF-shaped response | One screen aggregates multiple services | Partial response metadata, per-section freshness, shaped payloads | BFF becoming a hidden source of business logic drift |
State Ownership Model
| State class | Owner | Examples | Common pitfall |
|---|---|---|---|
| Server truth | API + server-state cache | Entities, permissions, availability | Copying into multiple client stores |
| Client view state | Component/local store | Popover open, selected row, input draft | Persisting ephemeral state globally |
| URL state | Router/query params | Query, filters, sort, page cursor | State not shareable/bookmarkable |
Server state vs client state vs URL state
Most frontend system design state management mistakes come from putting the same truth in too many places. Treat this table as the core server state vs client state frontend split.
| State type | Source of truth | Persistence | Common mistake |
|---|---|---|---|
| Server state | API response + server-state cache | Cache TTL, background refresh, invalidation events | Mirroring entities into a global UI store and losing freshness rules |
| Client UI state | Component or scoped UI store | Usually ephemeral; persist only drafts or user preferences | Putting modal, hover, focus, and optimistic flags into URL or server contracts |
| URL state | Router query params | Shareable across reload, back/forward, and links | Keeping filters, sort, and cursor only in memory so the page cannot be shared |
| Derived state | Computed from server, URL, or UI state | Recompute; do not store unless expensive and memoized | Persisting derived totals and creating stale duplicates |
UI States Matrix (Critical for Frontend)
| State | Trigger | What user sees | Telemetry signal |
|---|---|---|---|
| idle | No request yet | Prompt or default content | Initial load event |
| loading | Request in-flight | Skeleton/spinner with accessible announcement | Request start latency timer |
| success | Data received | Primary content rendered | Success rate and completion |
| empty | Valid response, zero items | Empty-state guidance + next action | Zero-result rate |
| error | Failure/timeout/unauthorized | Error message + retry path | Error rate by endpoint/route |
| stale | Cached data older than freshness policy | Stale badge while background refresh runs | Stale duration distribution |
| partial | One dependency failed in aggregate response | Partial data + degraded notice | Partial-response ratio |
Query Keys, Caching TTLs, and Invalidation
Cache policy example
| Query key pattern | TTL | Invalidate when | Notes |
|---|---|---|---|
['search', query, filters, sort] | 15-30s | Query/filter/sort changes, relevant mutation | Short TTL for high interaction flows |
['entity', id] | 60-120s | Entity update/delete, permission change | Stable detail reads with targeted invalidation |
['list', segment, cursor] | 30-90s | New create event affecting ordering | Cursor-aware invalidation avoids full reset |
What interviewers want to hear
- You define key shape before saying "we will cache."
- You combine time-based and event-based invalidation.
- You explicitly describe stale behavior and background refresh.
Pagination, Sorting, Filtering, and URL Sync
| Concern | Decision | Pitfall to avoid |
|---|---|---|
| Pagination | Prefer cursor pagination for mutable lists | Offset drift on frequently updated feeds |
| Sorting | Include sort token in query key and URL | Cache collisions across sort modes |
| Filtering | Normalize filter order in keys and URLs | Duplicate queries due to parameter order |
| URL sync | Keep shareable state in query params | State lost on refresh/back/forward |
Mutation Flows and Optimistic Updates
- Capture previous cache snapshot for affected keys.
- Apply optimistic patch locally for immediate UI feedback.
- Send mutation request with idempotency token where possible.
- On success, reconcile server response and clear temp markers.
- On failure, rollback snapshot and show actionable error state.
Script cue: "I will optimize read-your-writes UX with optimistic updates, but keep rollback explicit to avoid silent divergence."
Consistency and Sync Strategy
| Consistency level | Where to use | Frontend implication |
|---|---|---|
| Strong | Payments, inventory, permission-critical operations | Block speculative UI; wait for confirmed server state |
| Eventual | Feeds, analytics counters, recommendations | Allow stale view with explicit refresh semantics |
| Read-your-writes UX | User-triggered actions where instant feedback matters | Use optimistic patch + rollback guardrail |
Failure Modes and Recovery
| Failure mode | User-visible behavior | Data-model guardrail |
|---|---|---|
| Timeout under load | Show stale cache + retry affordance | Model stale flag + lastUpdated timestamp |
| Partial backend response | Render available sections with degraded notice | Model partial response metadata per segment |
| Mutation conflict | Conflict prompt with server-authoritative view | Version token and conflict status in contract |
| Permission drift | Disable restricted actions and refresh view | Role/scope fields as part of entity payload |
Security and Privacy Boundaries
- Classify fields: public, authenticated, privileged.
- Never leak privileged fields into broad list endpoints if detail view needs auth checks.
- Avoid caching sensitive payloads in long-lived shared layers.
- Design contracts so client cannot infer restricted data from error shape.
Observability and Data Quality Signals
| Signal | Metric | Alert direction |
|---|---|---|
| Freshness | Stale-state dwell time by route | Alert when stale duration exceeds SLO window |
| Correctness | Client/server mismatch rate after mutation | Alert on rollback spikes |
| Resilience | Partial-response ratio and timeout rate | Alert on sudden trend breaks |
| User impact | Primary task completion rate | Alert on significant drop after release |
Prompt-specific state and data decisions
Practice prompts are where frontend system design data flow becomes concrete. Name the entity model, cache key, invalidation trigger, and UI state for the prompt in front of you.
| Prompt | State and data decisions | Interview risk |
|---|---|---|
| Real-time Search | Query-keyed suggestion cache, latest-query-wins guard, URL query, stale and empty states | Showing results from an older request after the user typed a newer query |
| News Feed | Post/author/cursor entities, normalized cache, pagination keys, reaction optimistic updates | Duplicate feed items, cursor drift, or stale reactions after rollback |
| Dashboard Widgets | Widget entity, layout persistence, per-widget server state, user preference state | One widget refresh invalidating the whole dashboard or losing layout on reload |
| AI Chat | Draft state, message entities, streaming event schema, optimistic send, retry/reconnect state | Duplicated messages or lost drafts after network interruption |
| Design System Architecture | Token contracts, component API versions, package metadata, adoption telemetry | Breaking consumers because versioned contracts and migration state are unclear |
What to Say Out Loud (Data Model Script Cues)
- "I will define entities and ownership boundaries before discussing libraries."
- "I am separating server truth, UI state, and URL state to avoid sync confusion."
- "I will model all critical UI states: idle, loading, success, empty, error, stale, and partial."
- "I am defining query keys first so caching and invalidation stay predictable."
- "Trade-off here: shorter TTL improves freshness but increases backend load."
- "I will use optimistic updates only where rollback is safe and explicit."
- "For this flow, eventual consistency is acceptable; strong consistency is reserved for critical writes."
- "I am keeping shareable filters and pagination in URL state for deep links."
- "I will instrument stale time, mutation rollback rate, and partial responses to validate this model."
- "With data contracts locked, I can now move to interface behavior confidently."
Data Model Timebox for Interviews
45-minute interview
| Time range | What to do | Output artifact |
|---|---|---|
| 0:00-2:00 | Sketch top entities and relations | Entity map |
| 2:00-4:00 | Define state ownership boundaries | Ownership table |
| 4:00-6:00 | Set query keys, TTL, invalidation | Cache policy card |
| 6:00-8:00 | Cover UI states + mutation failure handling | UI states matrix + rollback notes |
60-minute interview
| Time range | What to do | Output artifact |
|---|---|---|
| 0:00-3:00 | Entity model with field-level contracts | Entity and contract sheet |
| 3:00-6:00 | State ownership and URL sync rules | Ownership and URL table |
| 6:00-9:00 | Caching and invalidation by use case | TTL and invalidation matrix |
| 9:00-12:00 | Mutation conflict, consistency, observability recap | Hardening checklist |
Quick Drill: Typeahead Data Model in 7 Minutes
| Minute | What to produce |
|---|---|
| 0-1 | Entity sketch: Suggestion, SearchResponse, ErrorPayload |
| 1-2 | State ownership split: server results, UI highlight index, URL query |
| 2-3 | UI states matrix including empty/error/stale/partial |
| 3-4 | Query key pattern and TTL decisions |
| 4-5 | Invalidation triggers for query change and mutation |
| 5-6 | Optimistic update and rollback notes for save/recent actions |
| 6-7 | Telemetry: latency, error, stale ratio, zero-result rate |
Before You Move to Interface
- Entities and relationships are explicit and bounded.
- Server truth, UI state, and URL state are clearly separated.
- All critical UI states are modeled, not implied.
- Cache keys, TTLs, and invalidation triggers are concrete.
- Mutation rollback and conflict handling are defined.
- Security, privacy, and observability considerations are included.
Data Model FAQ
What is a frontend state and data model in system design?
It is the part of a frontend system design answer where you define entities, API contracts, server state, client state, URL state, cache keys, invalidation, UI states, and mutation behavior.
How do I separate server state, client state, and URL state?
Keep server state in API-backed cache, transient interaction state in components or UI stores, and shareable navigation state such as search, filters, sort, and cursor in the URL.
What should frontend API contracts include?
Frontend API contracts should include stable IDs, timestamps or versions, pagination shape, error shape, stale or partial metadata, permission-sensitive fields, and the UI state each response can produce.
How should I explain cache invalidation in a frontend interview?
Define query keys first, then name TTLs, mutation-triggered invalidation, permission-change invalidation, background refresh behavior, and what the user sees when data is stale.
When should I use optimistic updates?
Use optimistic updates when the action is low risk, the rollback path is explicit, conflicts are modeled, and the UI can reconcile the server response without hiding divergence.