Build the mental model
A client is whatever makes the request — a browser, a mobile app, a desktop app, or even a server making a request to another server. A server is whatever receives the request and provides a service.
| Layer | Responsibilities |
|---|---|
| Frontend | UI, user interaction, forms/input, layout and style (no framework comparisons here) |
| Backend | authentication, business logic, database access, building API endpoints |
Not a rigid binary
Modern frameworks — server components, full-stack meta-frameworks — increasingly blur the line between frontend and backend.
Full-stack means being able to work across both layers when a task calls for it, not mastering every technology inside either one.
CLIENT/SERVER AND FRONTEND/BACKEND
----------------------------------
CLIENT --- request ---> SERVER
CLIENT <-- response ---- SERVER
In a typical web app:
BROWSER --> FRONTEND --> BACKEND --> DATABASE / SERVICES
(user) (UI layer) (logic) (data + other APIs)Connect it to a real scenario
The code example takes a task description string and classifies it as Frontend, Backend, Both, or Unclear using a simple keyword rule set.
- "Render a button" -> matches a frontend keyword -> Frontend
- "Validate a password / Query the database / Authorize a request" -> match backend keywords -> Backend
- "Animate a dropdown menu" -> matches "animat" -> Frontend
This is a simple heuristic, not a rigorous classifier — real tasks often straddle both layers, which is why the function includes a "Both" category.
Try the working example
const BACKEND_KEYWORDS = [
"database", "auth", "password", "server", "api endpoint",
"business logic", "authorize", "store data", "query",
];
const FRONTEND_KEYWORDS = [
"render", "button", "layout", "animat", "display",
"form field", "click", "style", "screen",
];
function classifyTask(task) {
const lower = task.toLowerCase();
const isBackend = BACKEND_KEYWORDS.some((k) => lower.includes(k));
const isFrontend = FRONTEND_KEYWORDS.some((k) => lower.includes(k));
if (isBackend && !isFrontend) return "Backend";
if (isFrontend && !isBackend) return "Frontend";
if (isFrontend && isBackend) return "Both (spans frontend and backend)";
return "Unclear";
}
const tasks = [
"Render a button on the page",
"Validate a password against the stored hash",
"Query the database for a user's orders",
"Animate a dropdown menu opening",
"Authorize a request using an API key",
"Display a form field's error message",
];
for (const task of tasks) {
console.log(`"${task}" -> ${classifyTask(task)}`);
}"Render a button on the page" -> Frontend
"Validate a password against the stored hash" -> Backend
"Query the database for a user's orders" -> Backend
"Animate a dropdown menu opening" -> Frontend
"Authorize a request using an API key" -> Backend
"Display a form field's error message" -> Frontend5-minute try-it
Add a new task string, "Style a button and save its click count to the database", and run it. Predict the result — notice it contains both "style" (a frontend keyword) and "database" (a backend keyword).
One important caution
Assuming frontend means only "appearance" — client-side logic, state management, and API calls are all part of frontend too
Treating frontend/backend as a rigid, framework-defined category, when modern frameworks routinely blur that boundary
MDN Web Docs — Client-Server overview — How the Web Works