This is Part 2 of my "From One User to One Million" series, where we'll build an understanding of System Design by following a simple application as it grows from a single user to millions. Instead of memorising technologies, we'll learn why they exist by solving real problems as they appear.
In the previous article, we followed the journey of a single request across the internet.
A user opened a browser, entered a website's address, and the request travelled through DNS before eventually reaching a server. The server processed the request, retrieved the required information from the database, and returned a response to the browser.
At first glance, the process looked surprisingly simple.
Browser
│
▼
DNS
│
▼
Server
│
▼
Database
│
▼
Server
│
▼
Browser
This simple flow forms the foundation of almost every modern web application.
However, if you look closely, you'll notice that we skipped over the most important part of the journey.
We said that the request reaches the server.
But what exactly is a server?
If you've just started learning web development, there's a good chance you've imagined a server as a giant machine sitting inside a massive data centre. Movies and YouTube videos often show endless rows of blinking computers, making servers feel like some mysterious piece of technology that's completely different from the computer sitting on your desk.
The reality is much less dramatic.
A server is simply another computer.
It has a CPU, RAM, storage, an operating system, and a network connection. Just like your laptop, it executes programs, stores files, and performs calculations.
So why do we give it a completely different name?
Because of what it does, not because of what it is.
Your laptop is designed primarily to serve you.
It opens your browser, runs your code editor, plays music, and stores your personal files. Most of the work it performs is initiated by you.
A server has a completely different responsibility.
Its job is to wait for requests from other computers and respond to them as quickly as possible.
That's why it's called a server.
It serves.
Once you understand this idea, many concepts in System Design immediately become less intimidating.
The cloud isn't magic.
A server isn't magic.
In most cases, it's simply another computer running somewhere else, waiting for requests from users all over the world.
Every Request Has Somewhere to Go
Let's return to the example from Part 1.
Imagine you're opening Instagram.
You tap the app icon and immediately see your home feed.
From your perspective, everything feels instantaneous.
Behind the scenes, however, your phone has just sent a request asking for your personalised feed.
The server receives that request and starts working.
But here's an interesting question.
What does the server actually do with it?
Does it immediately know which posts to show?
Does it somehow remember every user's feed?
Does it already have the answer waiting?
The answer is no.
The server has to figure everything out.
It first reads the request to understand what the user is asking for.
If you've already logged in, the request usually contains information that identifies who you are. Once the server knows your identity, it can begin executing the application's logic.
For Instagram, that logic might look something like this:
- Find the user's account.
- Check which people they follow.
- Fetch the latest posts from those accounts.
- Sort those posts.
- Prepare the final response.
Only after completing these steps does the server send the results back to your phone.
Notice something important here.
The server itself isn't deciding how Instagram works.
Your application is.
The server simply provides the environment where your application can run.
If your application is written using Django, Flask, Express.js, Spring Boot, Laravel, or ASP.NET, the server's job is to execute that code whenever a request arrives.
This is one of the biggest misconceptions beginners have.
People often say:
"The server checks the password."
In reality, your application checks the password.
The server simply runs the application that contains your code.
Understanding this distinction is incredibly important because, as we move deeper into System Design, we'll constantly separate the infrastructure from the application running on top of it.
A server is the stage.
Your application is the actor performing on it.
From Receiving a Request to Sending a Response
Now that we know what a server is, let's walk through what actually happens when it receives a request.
Imagine you're logging into your favourite application.
You enter your email and password, click the Login button, and wait for the next page to load.
It feels almost instantaneous.
But inside the server, a sequence of events has already begun.
The first thing that arrives at the server isn't your username or password.
It's an HTTP request.
Think of an HTTP request as a letter.
The letter doesn't just contain your message—it also contains important information about who sent it, where it should go, and what they're asking for.
A simplified login request might look something like this:
POST /login HTTP/1.1
Host: example.com
Content-Type: application/json
{
"email": "john@example.com",
"password": "********"
}
Don't worry if every line doesn't make sense yet.
For now, notice two things.
First, the browser tells the server what it wants.
In this case, it's asking to log in.
Second, it also sends the data required to perform that action.
Once this request reaches the server, something interesting happens.
The server itself doesn't know how to log users in.
It doesn't know what an email address is.
It doesn't know what a password is.
Those rules belong to your application.
The server's responsibility is to hand the request over to the application that's running on it.
You can imagine the process like this:
flowchart LR
Browser --> Server
Server --> Application
This might seem like a small detail, but it's one of the most important ideas in web development.
Many beginners use the words server and application interchangeably.
In reality, they are two different things.
The server provides the environment where everything runs.
The application contains the business logic that you've written.
If you're building a Django application, the server executes your Django code.
If you're using Express.js, it executes your JavaScript code.
If you're using Spring Boot, it executes your Java code.
The server doesn't decide whether a password is correct.
Your application does.
Once the application receives the request, it begins following the instructions you've written.
For a login request, those instructions might look something like this:
- Read the email address from the request.
- Search the database for a user with that email.
- Compare the submitted password with the stored password.
- If everything matches, generate a session or authentication token.
- Prepare a successful response.
Notice something interesting.
The application still doesn't have all the information it needs.
It knows what the user is asking for, but it doesn't know whether that user actually exists.
To answer that question, it needs help from another component.
The database.
The Database Knows What the Application Doesn't
Imagine you're trying to log in to an application.
The application has received your email address and password, but it still has one important question to answer.
"Does this user actually exist?"
The application can't answer that on its own.
When your application starts, it doesn't magically load every user's information into memory. If it did, applications with millions of users would quickly run out of RAM.
Instead, user information is stored permanently inside a database.
Whenever the application needs information, it asks the database for it.
You can think of the database as the application's long-term memory.
Whenever your application forgets something—or simply doesn't know it—it asks the database.
For a login request, the conversation between the application and the database is surprisingly simple.
The application might send a query like this:
SELECT email, password_hash
FROM users
WHERE email = 'john@example.com';
Again, you don't need to understand SQL in detail yet.
The important idea is this:
The application asks a question.
The database returns an answer.
If the database finds a user with that email address, it sends the stored information back to the application.
If it doesn't, it simply says,
"I couldn't find anyone with that email."
At this point, the application finally has everything it needs.
It compares the password you entered with the securely stored password hash.
If they match, the login is successful.
If they don't, the application returns an error.
Notice that the database never decides whether you should be allowed to log in.
It simply stores and retrieves information.
The application makes the decision.
This distinction is important because beginners often assume the database "handles authentication."
It doesn't.
The database stores data.
Your application decides what to do with that data.
Once the application has finished its work, it prepares a response for the browser.
If the login was successful, the response might contain a session token or some information about the logged-in user.
If the login failed, it might contain an error message explaining what went wrong.
Either way, the response travels back through the server until it reaches your browser.
The browser then reads that response and updates the user interface.
If everything went well, you see your dashboard.
If something failed, you see an error message asking you to try again.
The complete journey now looks like this.
flowchart LR
A[Browser] -->|HTTP Request| B[Server]
B --> C[Application]
C -->|Query| D[(Database)]
D -->|Data| C
C -->|HTTP Response| A
Although this entire process feels almost instantaneous, several different components have already worked together.
Each one has a clearly defined responsibility.
- The browser creates and displays the request.
- The server receives incoming requests.
- The application executes your business logic.
- The database stores and retrieves information.
Keeping these responsibilities separate is one of the reasons modern web applications are easier to build, maintain, and scale.
So far, we've only followed a single request.
One browser.
One user.
One login.
Everything works exactly as expected.
But what happens when this same sequence isn't happening once...
It's happening 100,000 times every second?
That's where things become interesting.
One Request Is Easy. A Million Are Not.
At this point, we've followed an entire request from beginning to end.
A user clicked Login.
The browser created an HTTP request.
The server received it.
The application executed your code.
The database returned the required information.
Finally, the server sent a response back to the browser.
Although it feels like a lot of work, modern servers can complete this entire process in just a few milliseconds.
For a single user, this is effortless.
Even if ten or a hundred people use the application at the same time, most servers won't have any trouble keeping up.
So where does the problem begin?
The answer is surprisingly simple.
Every request consumes resources.
Every time a request reaches the server, it needs some amount of CPU time to execute your application's logic. It needs memory to store temporary data while it's being processed. It uses network bandwidth to receive the request and send the response back to the user. If the application needs information from a database, that query also consumes time and resources.
One request doesn't consume much.
Neither do ten.
But every request adds a little more work.
Imagine you're the only customer at a coffee shop.
You walk in, place your order, and within a few minutes your coffee is ready.
Now imagine that one hundred customers walk into the same coffee shop at exactly the same time.
The coffee machine hasn't become slower.
The barista hasn't forgotten how to make coffee.
The only thing that has changed is the amount of work arriving at once.
Some customers will have to wait.
The exact same thing happens inside a server.
The server doesn't suddenly become less powerful.
It simply has more requests to process than it can handle at that moment.
As the number of incoming requests continues to grow, the server begins spending more time working and less time waiting for the next request.
Eventually, it reaches its limit.
Some requests begin waiting.
Others take much longer to complete.
If the traffic continues increasing, some requests may even fail because the server simply doesn't have enough resources to process them in time.
This is one of the most important ideas in System Design.
Applications rarely fail because a single request is difficult to process.
They fail because millions of simple requests arrive at the same time.
Once you understand this idea, many technologies that seemed complicated suddenly begin to make sense.
Load balancers don't exist because one request is difficult.
Caching doesn't exist because databases are slow.
CDNs don't exist because the internet is broken.
All of these technologies exist because, sooner or later, one server reaches its limits.
Understanding those limits is the first step towards understanding how modern applications scale.
Wrapping Up
In this article, we stepped inside the server and followed the complete lifecycle of a request.
We learned that a server isn't a magical machine hidden somewhere in the cloud. It's simply another computer whose primary job is to receive requests, run your application, communicate with the database when necessary, and send responses back to users.
We also discovered that the server itself doesn't contain your application's logic. It simply provides the environment where your code runs.
Finally, we saw that every request consumes resources. One request is easy to handle, but thousands—or even millions—of requests arriving at the same time create an entirely different challenge.
That challenge is exactly what System Design is all about.
In the next part of this series, we'll dive deeper into a question every engineer eventually asks:
How many requests can a single server actually handle before it reaches its limit?
We'll explore what determines that limit, why buying a bigger server isn't always the answer, and how these limitations eventually lead us to one of the most important concepts in System Design.
See you in Part 3.
Top comments (0)