“Back then, one file was enough…”
PHP, which I used in college, was incredibly convenient. You could put HTML tags in a single index.php file, open <?php ?> in the middle of it, and write your database query code right there. There was no strict divide between frontend and backend. Once you declared a variable, you could use it anywhere in the HTML, and there was hardly any chance of data communication errors.
But when I switched in practice to a stack built around Vue.js on the frontend and Spring Boot on the backend, that was the beginning of hell.
“I definitely started the Spring server locally, and the Vue screen is running too, so why isn’t the data coming through?”
The Chrome DevTools console was covered in bright red error messages.
Access to XMLHttpRequest at ... has been blocked by CORS policy
What exactly is this thing called CORS that keeps blocking my data? And why did we abandon the convenient old approach where one file handled everything, only to split frontend and backend apart on purpose?

Who should do the cooking? (SSR vs CSR)
To understand this shift, we need to understand who is responsible for preparing the “dish” called a web page, or HTML. That is exactly the difference between SSR (Server Side Rendering) and CSR (Client Side Rendering).
1. SSR: a ready-made lunchbox (PHP, JSP)
2. CSR: a meal-kit delivery (React, Vue)
[Tip] CSR and SPA are not exactly the same thing
People often use the terms interchangeably, but technically they are different.
In practice, we usually use CSR in order to build an SPA. In other words, because we want to avoid full-page flicker by using a single page (SPA), we choose a rendering approach where the browser redraws the necessary parts itself (CSR).
The reason we use Vue.js or React is user experience. To make a website behave smoothly like a smartphone app, we moved the main act of preparing the “dish” from the server to the browser.

CORS, the security guard that blocks uninvited guests
Once frontend (Vue) and backend (Spring) are separated, we effectively end up with two different houses.
That is where the problem begins. For security reasons, the web browser follows a basic rule: “Do not trust resources coming from a different Origin too easily.” That is the SOP, or Same Origin Policy.
Think about it. Suppose I am logged in to Naver, and a site built by a hacker secretly sends a request to the Naver server saying, “Hand over my private information.” If the browser did not block that, all my data would be exposed.
So the browser blocks requests by default whenever the origin, meaning the domain and port, is different. But for development, we intentionally split things across ports. We are only trying to use our own data, yet the browser, acting like a security guard, says, “Your port doesn’t match. Entry denied.” That is what a CORS (Cross-Origin Resource Sharing) error really is.
[Code Verification] Issuing an access pass
The solution is actually simple. The server, the backend, writes a pass for the browser, the security guard, saying: “This one is a guest I invited. Please let them in.”
In Spring Boot, that pass can be issued through a single configuration file.
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 1. For every API path
.allowedOrigins("http://localhost:8080") // 2. Allow requests from this origin
.allowedMethods("GET", "POST", "PUT", "DELETE") // 3. Allow these types of requests
.allowCredentials(true); // 4. Cookies and credentials are allowed
}
}
Analysis:
One thing to be careful about: do not get lazy and open everything with allowedOrigins("*"). That is like leaving your front door wide open with a sign that says, “Welcome, thieves.”
Practical advice: when should you use what?
So does that mean CSR, with Vue or React, is always the right answer? No. In real work, the choice depends on the goal.
Closing: crossing the boundary
The old PHP-style “big family under one roof” was convenient, but the more complicated things became, the harder it was to manage. The modern setup, two separate households, frontend and backend, is more annoying because of communication issues like CORS, but it allows each side to focus on its own role.
So the next time you run into a CORS error, try not to get angry. The browser is not bullying you. It is simply carrying out a strict inspection to protect your house, your server.
Now the path between frontend and backend is open. Data can move back and forth. But where exactly is that data stored on the server? In the old days, I could just throw a query at the database and get what I needed. In Spring, though, things like JPA and Entity suddenly get in the way and seem to stop you from writing SQL directly.
Next time, let’s look at how the “textbook way” of database design, normalization, can actually become a bottleneck in real-world work, and why JPA tries so hard to hide SQL from you.