00:00

Client-Server Architecture in System Design

Last updated: 14 min read

Client-server architecture is a model in which clients request services or data and servers provide them over a network. Every time you open a website, check email, stream a video or use a banking app, a client on your device is talking to servers somewhere else. It is the most widely used architecture on the internet and the starting point for nearly every system design.

This tutorial explains the parts of a client-server system, how a request travels from client to server and back, the 1-tier, 2-tier, 3-tier and n-tier variations, thin and thick clients, real-world examples, and how to build a simple client and server in Java. It also covers how client-server systems scale, their advantages and drawbacks, and how they compare with peer-to-peer systems.

1. What Is Client-Server Architecture?

Think of a restaurant. You (the client) look at the menu and place an order. The kitchen (the server) prepares the food and sends it back. You never walk into the kitchen, and the kitchen never decides what you eat. The waiter carrying orders back and forth is like the network, and the menu, with its agreed list of dishes, is like the protocol.

In computing, client-server architecture divides work between two roles:

  • The client starts the conversation. It sends a request and waits for a response.
  • The server waits for requests, processes them, and sends back responses. One server usually serves many clients at the same time.

The server owns the shared resources: the data, business rules and heavy processing. Clients focus on interacting with users. This central ownership is what makes the model easy to secure, update and manage.

The client-server model Three clients, a web browser, a mobile app and a desktop app, send requests across the internet to a server. The server reads and writes data in a database and returns responses to the clients. Web browser Mobile app Desktop app CLIENTS Network internet / LAN Server business logic req / res Database SERVER SIDE
Figure 1: Many different clients send requests over the network to a central server, which uses a database and returns responses.

2. Key Components

ComponentRoleExamples
ClientSends requests, shows results to the userWeb browsers, mobile apps, desktop apps, IoT devices, other services
ServerListens for requests, runs logic, returns responsesWeb servers, application servers, database servers, mail servers
NetworkCarries messages between client and serverThe internet, an office LAN, a mobile network
ProtocolAgreed rules for the message format and orderHTTP/HTTPS, WebSocket, gRPC, SMTP, DNS, database wire protocols
Data storeKeeps persistent data for the serverMySQL, PostgreSQL, MongoDB, object storage

Note that "client" and "server" are roles, not types of hardware. A server process can run on a laptop, and a back-end service acts as a client when it calls another service or a database.

3. How a Client-Server Request Works

Let us follow what happens when a user opens https://shop.example.com/products in a browser:

The journey of a web request A sequence diagram with three participants: browser, DNS server and web server. The browser asks DNS for the IP address of shop.example.com and gets 203.0.113.10. It then opens a TCP connection and performs a TLS handshake with the web server, sends GET /products, the server processes it and queries the database, and returns 200 OK with the page or JSON. Browser DNS Web Server 1. IP of shop.example.com? 2. 203.0.113.10 3. TCP connection + TLS handshake 4. GET /products 5. Process request check auth, query database 6. 200 OK + HTML or JSON 7. render page
Figure 2: A typical request: look up the server's address, open a secure connection, send the request, let the server process it, and receive the response.
  1. Find the server: the browser asks DNS to translate the domain name into an IP address (often answered from a cache).
  2. Get the address: DNS returns the IP address of the server or its load balancer.
  3. Connect: the browser opens a TCP connection and performs a TLS handshake so the conversation is encrypted.
  4. Send the request: an HTTP request such as GET /products, with headers like cookies and accepted formats.
  5. Process: the server checks who the user is, runs business logic, and reads from the database or cache.
  6. Respond: the server returns a status code (such as 200 OK) and a body, such as HTML or JSON.
  7. Display: the browser renders the page, and may send more requests for images, scripts and styles.

This request-response pattern is the heart of client-server systems. When the server needs to push updates without being asked, such as chat messages, techniques like WebSockets extend the model.

4. Types of Client-Server Architecture

Client-server systems are often described by how many tiers (separately running layers) they have.

1-tier architecture

The user interface, business logic and data all live in one application on one machine, such as a desktop spreadsheet that saves to a local file. Simple, but there is no sharing between users.

2-tier architecture

The client talks directly to the database server. The client application contains the user interface and most of the business logic. This was common for internal office applications. It is fast for a small number of users, but every client needs database access and credentials, business rules are spread across many installed clients, and it does not scale to large numbers of users.

3-tier architecture

A middle application tier sits between clients and the database. This is the standard model for web applications:

Three-tier client-server architecture Three tiers from left to right. Presentation tier: browsers and mobile apps showing the user interface. Application tier: application servers running business logic and APIs. Data tier: a database storing data. Arrows show requests flowing from presentation to application to data and results flowing back. PRESENTATION TIER Browser Mobile app APPLICATION TIER App Server business logic, APIs DATA TIER Database stores data HTTP / JSON SQL / driver
Figure 3: In a 3-tier architecture, the client handles presentation, the application server handles business logic, and the database handles storage. Clients never talk to the database directly.
  • Presentation tier: what the user sees and interacts with.
  • Application (logic) tier: validates input, applies business rules, coordinates work and exposes APIs.
  • Data tier: stores and retrieves data.

Because each tier is separate, you can scale, update and secure them independently. The database is hidden from the internet, and business rules live in one place.

N-tier architecture

Large systems add more layers: a CDN, load balancers, an API gateway, caching tiers, separate services, message queues and search engines. Each extra tier solves a specific problem, such as speed, scale or security, at the cost of more moving parts. Microservices can be seen as an n-tier design split further by business capability.

ModelStructureStrengthsWeaknessesTypical use
1-tierEverything on one machineSimplestNo sharing or central controlStandalone desktop tools
2-tierClient ↔ databaseFast, simple for small teamsWeak security, poor scaling, logic in every clientSmall internal apps
3-tierClient ↔ app server ↔ databaseSecure, maintainable, scalableAn extra network hopMost web and mobile applications
N-tierMany specialised layersHighly scalable and flexibleMore complex to build and operateLarge-scale platforms

5. Thin Clients vs Thick Clients

Client-server systems also differ in how much work the client does:

AspectThin clientThick (fat) client
Where logic runsMostly on the serverMuch of it on the client device
Device requirementsLow; little processing or storageHigher; needs CPU, memory and storage
UpdatesChange the server once, everyone gets itEach client must be updated
Offline useUsually not possibleOften possible, syncs later
Network dependencyHigh, every action needs the serverLower, many actions work locally
ExamplesServer-rendered web pages, remote desktopsVideo games, IDEs, offline-capable mobile apps

Modern single-page web apps and mobile apps sit in between: they run a lot of interface logic on the device but keep business rules and data on the server.

6. Real-World Examples

  • The web: browsers (clients) request pages and APIs from web servers using HTTP.
  • Email: mail apps send messages to a mail server with SMTP and fetch them with IMAP.
  • Databases: your Spring Boot application is a client of the MySQL or PostgreSQL server.
  • DNS: every device is a DNS client that asks DNS servers to resolve domain names.
  • Online banking: the banking app sends requests to the bank's servers, which own the accounts and enforce every rule.
  • Multiplayer games: game clients send player actions to an authoritative game server that decides what really happened, which prevents cheating.
  • File storage: cloud drive apps upload to and download from storage servers.

7. Building a Simple Client and Server in Java

At the lowest level, a client and server talk over a socket, an endpoint for a network connection identified by an IP address and port. The server below listens on port 5000 and understands two text commands. It uses virtual threads (Java 21) so each connected client is served on its own lightweight thread.

TimeServer.java
package com.javabytechie.clientserver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.time.LocalTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TimeServer {

    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(5000);
             ExecutorService workers = Executors.newVirtualThreadPerTaskExecutor()) {
            System.out.println("Server listening on port 5000");
            while (true) {
                Socket client = server.accept();               // wait for the next client
                workers.submit(() -> handle(client));          // serve it on its own virtual thread
            }
        }
    }

    private static void handle(Socket socket) {
        System.out.println("Client connected: " + socket.getRemoteSocketAddress());
        try (socket;
             BufferedReader in = new BufferedReader(
                     new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
             PrintWriter out = new PrintWriter(
                     new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true)) {

            String request;
            while ((request = in.readLine()) != null) {
                switch (request.trim().toUpperCase()) {
                    case "TIME" -> out.println("OK " + LocalTime.now().withNano(0));
                    case "BYE"  -> { out.println("OK goodbye"); return; }
                    default     -> out.println("ERROR unknown command '" + request + "'");
                }
            }
        } catch (IOException e) {
            System.out.println("Connection problem: " + e.getMessage());
        } finally {
            System.out.println("Client disconnected");
        }
    }
}
TimeClient.java
package com.javabytechie.clientserver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class TimeClient {

    public static void main(String[] args) throws IOException {
        try (Socket socket = new Socket("localhost", 5000);
             BufferedReader in = new BufferedReader(
                     new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
             PrintWriter out = new PrintWriter(
                     new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true)) {

            for (String command : List.of("TIME", "WEATHER", "BYE")) {
                out.println(command);                          // send a request
                String response = in.readLine();               // wait for the server's response
                System.out.println("Sent: " + command + "  ->  Received: " + response);
            }
        }
    }
}

Start TimeServer first, then run TimeClient in another terminal:

Client output
Sent: TIME  ->  Received: OK 05:22:47
Sent: WEATHER  ->  Received: ERROR unknown command 'WEATHER'
Sent: BYE  ->  Received: OK goodbye
Server output
Server listening on port 5000
Client connected: /127.0.0.1:50358
Client disconnected

This tiny program shows every element of the model: the server listens and owns the logic, the client starts the conversation, and both follow a simple protocol (one text line per request and per response). HTTP, SMTP and database protocols are just richer versions of the same idea.

8. A Client-Server Example with Spring Boot REST

In real applications you rarely write raw sockets. HTTP and JSON are the common protocol, and Spring Boot handles the networking. Here is a small product API (the server) and a Java client calling it:

ProductController.java (server)
package com.javabytechie.clientserver;

import java.math.BigDecimal;
import java.util.Map;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/products")
public class ProductController {

    public record Product(long id, String name, BigDecimal price) { }

    private final Map<Long, Product> catalogue = Map.of(
            1L, new Product(1, "Mechanical Keyboard", new BigDecimal("4499.00")),
            2L, new Product(2, "USB-C Hub", new BigDecimal("1899.00")));

    @GetMapping("/{id}")
    public ResponseEntity<Product> findById(@PathVariable long id) {
        Product product = catalogue.get(id);
        return product != null ? ResponseEntity.ok(product) : ResponseEntity.notFound().build();
    }
}
ProductClient.java (client)
package com.javabytechie.clientserver;

import java.math.BigDecimal;

import org.springframework.web.client.RestClient;

public class ProductClient {

    record Product(long id, String name, BigDecimal price) { }

    public static void main(String[] args) {
        RestClient client = RestClient.create("http://localhost:8080");

        Product product = client.get()
                .uri("/api/products/{id}", 1)
                .retrieve()
                .body(Product.class);

        System.out.println("Received from server: " + product);
    }
}
Output
Received from server: Product[id=1, name=Mechanical Keyboard, price=4499.00]

The server exposes a clear contract (GET /api/products/{id} returning JSON), and any client, whether a browser, a mobile app or another service, can use it without knowing how the server stores its data.

9. Scaling Client-Server Systems

A single server eventually runs out of capacity. Client-server systems grow by adding layers in front of and behind the application:

A scaled client-server system Clients reach a CDN for static files and a load balancer for API calls. The load balancer spreads requests across three application servers. The application servers read from a cache and use a primary database with a read replica. Clients CDN static files Load Balancer App Server 1 App Server 2 App Server 3 Cache (Redis) Primary database Read replica replicate
Figure 4: A scaled client-server design: a CDN serves static files, a load balancer spreads requests over several identical servers, and a cache and read replica protect the database.
  • Vertical scaling: give the server more CPU and memory. Easy, but limited and creates a single point of failure.
  • Horizontal scaling: run several identical servers behind a load balancer. This works best when servers are stateless, keeping session data in a shared store or token instead of server memory.
  • Caching: keep frequently requested data in memory (Redis, Memcached) and static files in a CDN.
  • Database scaling: add read replicas, then shard when writes or data size outgrow one server.
  • Asynchronous processing: move slow work, like sending emails or generating reports, to background workers through a message queue.

10. Advantages of Client-Server Architecture

  • Centralised control: data, rules and security policies live on servers you manage.
  • Easier security: authentication, authorisation, encryption and auditing are enforced in one place, and sensitive data never needs to live on user devices.
  • Simple updates: change the server and every client benefits immediately, especially with thin and web clients.
  • Scalability: servers can be scaled up or out independently of clients.
  • Data integrity: one authoritative copy of the data avoids conflicting versions.
  • Separation of concerns: client and server teams can work independently against an agreed API.
  • Client variety: one server can serve web, mobile, desktop and partner clients at the same time.

11. Disadvantages and Challenges

  • Single point of failure: if the server, or a component it depends on, goes down, every client is affected. Redundancy and failover are needed.
  • Server bottleneck: heavy traffic can overload the server, requiring load balancing and scaling.
  • Network dependency: clients cannot work without a connection, and latency affects every interaction.
  • Infrastructure cost: servers, databases, bandwidth and operations teams cost money, and costs grow with users.
  • Attractive target: a central server holding everyone's data is a prime target for attackers, so it must be well protected.

12. Client-Server vs Peer-to-Peer

AspectClient-ServerPeer-to-Peer (P2P)
RolesFixed: clients request, servers provideEvery peer can both request and provide
ControlCentralisedDecentralised
Data locationOn serversSpread across peers
ScalingAdd server capacity as users growCapacity grows naturally as peers join
Single point of failureYes, unless made redundantNo central point
Security and managementEasier, enforced centrallyHarder, peers are untrusted
Cost for the providerHigher infrastructure costLower, users share resources
ExamplesWebsites, banking, email, SaaS productsBitTorrent, blockchain networks, some video-call paths

Read the Peer-to-Peer Architecture tutorial for a deeper look at the alternative.

13. Best Practices

  • Keep servers stateless where possible so they can be scaled horizontally and replaced freely.
  • Never trust the client: validate every input and enforce every permission on the server.
  • Use HTTPS for all client-server traffic.
  • Define clear, versioned APIs so clients and servers can evolve independently.
  • Set timeouts and retries with backoff on clients, and make retried operations idempotent.
  • Remove single points of failure with multiple server instances, load balancers and database replicas.
  • Cache aggressively at the right layers: browser, CDN, application cache.
  • Monitor latency, error rates and throughput from both the server side and, where possible, the client side.

14. Summary

  • Client-server architecture splits work between clients that request and servers that provide, communicating over a network with an agreed protocol.
  • A request typically involves a DNS lookup, a secure connection, a request, server processing and a response.
  • Systems range from 1-tier to n-tier; the 3-tier model (presentation, application, data) is the standard for web applications.
  • Thin clients rely on the server; thick clients do more work locally.
  • The model offers central control, security and easy updates, but needs redundancy and scaling to avoid bottlenecks and single points of failure.

Almost every system you design will be client-server at its core; the art is in how you scale and protect the server side. Open the FAQ tab for answers to common questions about client-server architecture.