client-side state VS server-side state
Definitions
| Term | What it is |
|---|---|
| Client-side state | Data that lives only in the browser, is managed by React itself, and exists independently of the server. |
| Server-side state | Data that is stored on the server (in a database, an API, etc.) and must be loaded, updated, or synchronized with the client. |
1. Client-side state
This is everything that exists only on the frontend,
and React itself controls it through useState, useReducer, useContext, etc.
Examples of client state:
- Whether a modal is open (
isModalOpen) - The current filter or sort order
- The selected tab
- Text entered by the user but not yet submitted
- Form validation
- Theme state (
dark/light) - Data in localStorage
This data does not need to be synchronized with the server. It lives in the browser's memory and disappears on page reload.
2. Server-side state
This is data that belongs to the server, and the client only loads, displays, and sometimes modifies it.
Examples:
- A list of users from an API
- Products in a store
- User profile data
- Comments on a post
- Account balance
- Any information stored in a database
This data:
- is obtained asynchronously (
fetch,axios,graphql,react-query,trpc), - can change on the server without the client's knowledge,
- requires updating (refetching) on certain events.
3. Key differences
| Characteristic | Client-side state | Server-side state |
|---|---|---|
| Where it is stored | In the browser's memory | On the server / API |
| Who "owns" the data | The client | The server |
| How it updates | Immediately via setState | Via an HTTP request (fetch, axios, etc.) |
| Can it change "on its own"? | No | Yes (other users, processes) |
| Does it need to be synchronized | No | Yes (via refetch or web sockets) |
| Examples | modals, filters, current tab | list of products, posts, user profile |
| Lost on reload | Yes | No (data is preserved on the server) |
Example for clarity
Client-side state
const [isModalOpen, setIsModalOpen] = useState(false);The modal opens and closes - everything lives in React. The server doesn't care.
Server-side state
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("/api/users")
.then(res => res.json())
.then(setUsers);
}, []);Here the data comes from an external source (an API). If someone adds a new user, the server updates, but the client doesn't know yet, until it makes another request (a refetch).
4. Why it matters to separate these
- Different update requirements
- Client state updates instantly via
setState. - Server state requires a network request → asynchronous.
- Different tools
- Client state →
useState,useReducer,useContext, Zustand, Redux Toolkit. - Server state →
React Query,SWR,Apollo,tRPC,RTK Query.
- Different "data lifetime"
- Client state - lives as long as the component is mounted.
- Server state - can be cached, refetched, invalidated.
- Different caching strategy
- Client state: no point caching it, it's local UI data.
- Server state: must be cached, so the API isn't hit on every render.
5. The modern approach: "divide and conquer"
Keep local state as close to the UI as possible
(useState, useReducer, useContext)
And move server state into specialized tools that know how to:
- cache requests,
- refetch on changes,
- synchronize data when a tab regains focus,
- optimistically update the interface.
Examples:
React Query (TanStack Query)
SWR (Next.js)
Apollo Client (GraphQL)
RTK Query (Redux)Example with React Query
import { useQuery } from "@tanstack/react-query";
function UsersList() {
const { data, isLoading, error } = useQuery({
queryKey: ["users"],
queryFn: () => fetch("/api/users").then(res => res.json()),
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
return (
<ul>
{data.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}Here data is server-side state,
but React Query manages its caching, refetching, and synchronization.
Summary
| Client-side state | Server-side state | |
|---|---|---|
| Where it lives | In React / the browser | On the server |
| How it updates | Immediately (setState) | Via a request |
| Can go stale without the client knowing | No | Yes |
| Tools | useState, useReducer, useContext, Zustand | React Query, SWR, RTK Query, Apollo |
| Examples | modal, filter, theme | posts, products, profile |
| Needs refetching | No | Yes |
| Render on update | Immediately | After the server responds |
A simple analogy
Client state is like a "draft" on your desk: you write notes, edit quickly, nothing gets synchronized.
Server state is like a document in the cloud (Google Docs): it is stored on the server, may change for other users, and you need time to get the up-to-date version.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.