Full-Stack Integration & Deployment — Fundamentals
Making the first real call: frontend to backend over HTTP
Every full-stack request starts the same way — the frontend, running in the browser, makes an HTTP request to a URL the backend is listening on. Nothing about this is new mechanically (you've made fetch calls before, and you've written Express routes before); what's new is that the two sides are now genuinely separate programs, often on separate ports even locally, and always on separate origins once deployed.
The frontend never imports the backend's code, and the backend has no idea a React component exists — the only thing connecting them is this HTTP contract: a URL, a method, a request/response shape. Get that contract wrong on either side and nothing about the other side's code quality matters.
CORS: a real browser security mechanism, not an arbitrary error
CORS (Cross-Origin Resource Sharing) exists because browsers, by default, block JavaScript running on one origin from reading responses from a different origin — otherwise, any malicious website's JavaScript could quietly call your bank's API using your logged-in session cookies and read the response. An origin is the combination of protocol, domain, and port — http://localhost:3000 and http://localhost:4000 are different origins, even on the same machine, which is exactly why you can hit this locally, not just after deployment.
The critical mental model: the request frequently still reaches your backend. CORS is the browser refusing to hand the response back to your frontend JavaScript, unless the backend explicitly said (via response headers) that the calling origin is allowed to read it.
Never combine origin: '*' with credentials: true — browsers reject that combination outright, and for good reason: it would mean "any site on the internet can make authenticated requests on a logged-in user's behalf."
Environment variables: frontend vs. backend is a real security boundary
This academy's Next.js technology already introduced the NEXT_PUBLIC_ convention — full-stack integration is where that convention's actual stakes become concrete. A backend environment variable (a database connection string, a JWT signing secret, a third-party API key) lives only on the server and is never sent to the browser. A frontend environment variable, once built, is baked directly into the JavaScript bundle shipped to every visitor — genuinely readable by anyone who opens dev tools, regardless of how it's named.
The rule that actually matters: if a value must stay secret, it belongs on the backend, full stop — never as a NEXT_PUBLIC_ (or equivalent) frontend variable, no matter how convenient it would be to read it directly from a component.
Passing an auth token from frontend to backend, on every request
A backend route protected by authentication middleware needs proof, on every single request, that the caller is who they claim to be — and HTTP itself is stateless, so that proof has to be actively attached each time, not assumed from a previous request.
Forget to attach the header on the frontend, or forget to apply requireAuth on a route that should have it, and both mistakes produce the exact same visible symptom — a 401 — which is why understanding the whole chain matters more than memorizing either half alone.
AI-assisted development in a real full-stack workflow
Using an AI coding assistant (GitHub Copilot, Claude Code, Cursor, and similar tools) is genuinely standard professional practice in full-stack development in 2026, not a shortcut to be embarrassed about — but it's a real skill with a real learning curve, not just "typing less."
Where an AI assistant is a strong, low-risk fit:
Where human judgment has to stay in the loop, deliberately:
The concrete practice: prompt for a specific, scoped change ("add input validation to this Express route using zod, matching the shape of this schema") rather than an open-ended one ("build me an API"), and review every line of what comes back the same way you'd review a teammate's pull request — because in a real interview, "the AI wrote it" is never an acceptable answer for a line of code you can't explain.
Basic full-stack project structure: monorepo vs. separate repos
Briefly, since this is mostly a deployment/tooling decision rather than a deep architectural one: a monorepo keeps frontend and backend in one repository (often in frontend/ and backend/ subdirectories, or as a Next.js app with API routes as the backend entirely), which simplifies coordinated changes and often simplifies deployment when both are deployed together. Separate repos keep them fully independent, which fits better when frontend and backend genuinely have separate teams, release cadences, or deployment targets. Most solo and small-team projects start as a monorepo — the coordination overhead of separate repos isn't worth paying until a team's size or deployment needs actually demand it.
Try It (2 Minutes)
Take a protected route from a backend project you've already built in this academy's Express technology. Add console.log(req.headers.authorization) at the very top of its route handler, then call it from the frontend once with the token attached and once without. Watch both the different console output on the backend and the different HTTP status returned to the frontend — that's the entire auth-token handshake made visible in under two minutes.

