Frontend Architecture
Rendering strategies, and the state distinction that simplifies everything.
Questions
Easy / Med / Hard
Your accuracy
Two decisions shape a frontend codebase more than any others: where rendering happens, and how you think about state.
Rendering strategies. Client-side rendering ships an empty shell and builds the page in the browser — simple to host, poor for first paint and for anything that needs indexing. Server-side rendering builds HTML per request, so content arrives fast and personalised, at the cost of server work on every view. Static generation renders at build time: the fastest and cheapest thing possible, limited to content known in advance. Incremental regeneration serves static pages and refreshes them on a schedule or on demand, which covers most content that changes occasionally.
These are per-route decisions, not per-application ones. A marketing page wants static; a dashboard wants client-side or server-rendered; a product page wants incremental.
The state distinction that matters most: server state is a cache of data that lives somewhere else. Client state is genuinely owned by the UI — which tab is open, what is in this form, is the menu expanded.
Most frontend complexity comes from treating server state as client state: fetching into a global store, then hand-writing loading flags, error flags, staleness, refetching, and invalidation. That is a caching problem, and caching problems have known solutions. Using a data-fetching library for server state and keeping your store for genuine client state removes a startling amount of code.
Colocate state as low as possible. Lift it only when something above genuinely needs it. State that lives higher than necessary re-renders more of the tree than necessary and makes components harder to move.
Hydration is not free. Server-rendered HTML appears fast and is not interactive until its JavaScript has downloaded and run — a page can look ready and ignore clicks, which users experience as broken rather than slow. Shipping less JavaScript, or none for static regions, is the direct fix.