LogIn
I don't have account.

System Design Basics: High Level Design (HLD) vs Low Level Design (LLD)

Rashmi Khatri
6 Views

Let me tell you about a project where skipping this distinction cost us real time, not a hypothetical one.

A team I was part of needed to build an automated campaign service, something that would listen for events (like "a customer joined a segment") and trigger a chain of downstream actions across several other services. Everyone was excited and everyone wanted to start coding fast. We split into two groups. One group started writing the event schema and the database tables for tracking campaign state. The other group started writing the actual service logic that would process events and call downstream APIs.

Two weeks in, we sat down to integrate the two halves and it fell apart almost immediately. The database group had assumed every event would be processed strictly in the order it arrived, so they hadn't included any sequence number or ordering guarantee in their schema. The service-logic group had assumed the messaging system would handle ordering for them automatically, so their code had no logic to check or enforce order either. Neither assumption was written down anywhere. Neither group had done anything wrong on its own they just never agreed, at a high level, on how the pieces would fit together before diving into the low-level details of building each piece.

That gap has a name and once you know it, you'll never unsee it in a project again: we had jumped straight into Low-Level Design the classes, the schemas, the specific logic without ever agreeing on the High-Level Design the big picture of how components would talk to each other and what guarantees they could rely on. This article exists so you don't repeat that two-week mistake.

  • System Design is the process of planning how a software system will be built, before you start writing code, similar to how a building is planned before construction begins.
  • High-Level Design (HLD) is the big-picture plan, which major components exist, how they talk to each other and what technology each one uses. Think of it as a city's master plan.
  • Low-Level Design (LLD) is the detailed, close-up plan, actual classes, functions, database tables and API contracts. Think of it as the detailed blueprint for one specific building in that city.
  • You need both. HLD without LLD leaves engineers guessing how to actually build each piece. LLD without HLD risks building pieces that don't fit together at all which is exactly what happened in the real story that opens this article.

What Is System Design, Really?

System Design is simply the practice of planning a software system's structure and behavior before you start building it deciding what pieces exist, how they connect and how they'll handle real-world conditions like heavy traffic, failures or growth.

Here's a comparison that makes this click immediately for most people: imagine building a house. Before a single brick is laid, an architect draws up a master plan where the bedrooms go, where the kitchen goes, how many floors, where the main water line enters the property. That's the big-picture plan. Separately, an electrician needs a much more detailed plan exactly where every wire runs, which switch controls which light, what gauge of wire is needed for the kitchen versus the bedroom. That's the detailed, close-up plan. Both plans matter. The architect's plan without the electrician's detail means nobody knows exactly how to wire the house. The electrician's detail without the architect's overall plan means the wiring might get built for a kitchen that ends up somewhere completely different once the actual floor plan is finalized.

In software, the architect's big-picture plan is called High-Level Design (HLD) and the electrician's detailed plan is called Low-Level Design (LLD). Here's where both sit inside the overall process, from the moment a requirement comes in to the moment it ships:

                  Requirement Gathering
                    (what does the user
                       actually need?)
                            |
                            v
                 +----------------------+
                 |  High-Level Design   |   <-- the big picture:
                 |         (HLD)        |       boxes, arrows,
                 +----------+-----------+       tech choices
                            |
                            v
                 +----------------------+
                 |  Low-Level Design    |   <-- the close-up:
                 |         (LLD)        |       classes, schema,
                 +----------+-----------+       API contracts
                            |
                            v
                     Implementation
                     (writing the code)
                            |
                            v
                         Testing
                            |
                            v
                       Deployment

Notice HLD and LLD sit right in the middle, between "we know what's needed" and "we're actually writing code." Skip either one and you get exactly the kind of gap described in the story above two teams building pieces that technically work on their own, but were never agreed to fit together.

What Is High-Level Design (HLD)?

High-Level Design describes the overall architecture of a system the major components, how they communicate and the key technology decisions without getting into the specific code, classes or exact database columns yet.

A real HLD document for something like an online food ordering platform would typically answer questions like these:

  • What are the major components? (a customer-facing app, a restaurant-facing app, an order management service, a payment service, a notification service)
  • How do these components talk to each other? (REST APIs, a message queue for asynchronous events, a shared database or separate databases per service)
  • What are the big technology choices? (which database type, whether to use a message broker like Kafka, whether the system is a monolith or built from microservices)
  • How will the system handle scale and failure? (load balancers, caching layers, database replication, backup regions)

Notice that none of this mentions a single class name, a specific database column or a line of code. HLD is intentionally zoomed out its entire purpose is to make sure every team and every component, agrees on the shape of the system and how the pieces fit together, exactly the agreement my team skipped in the story above.

What Is Low-Level Design (LLD)?

Low-Level Design describes the internal, detailed structure of one specific component the actual classes, functions, database schema and API contracts needed to build it.

Continuing the food ordering example, an LLD document for just the "Order Management Service" (one single box from the HLD diagram) would typically include:

  • The actual classes involved Order, OrderItem, OrderStatus, PaymentDetails and how they relate to each other.
  • The exact database table structure column names, data types, primary and foreign keys.
  • The exact API contract request and response formats for endpoints like POST /orders or GET /orders/{id}.
  • The specific logic and design patterns used for example, using a State design pattern to manage an order moving through statuses like PLACED, CONFIRMED, OUT_FOR_DELIVERY, DELIVERED.

This is the level of detail an engineer needs to actually sit down and write the code and it's also detailed enough that a good LLD can be directly translated into working software with far fewer surprises along the way which is exactly what was missing from the database team's schema in my story, since "does the order in which events arrive matter" is a Low-Level Design decision that should have been locked down explicitly, in writing, before anyone started coding.

HLD vs LLD Comparison Table

High-Level Design (HLD) Low-Level Design (LLD)
Zoom level The whole system, big picture One component, in detail
Answers the question "What are the pieces and how do they connect?" "Exactly how is this one piece built?"
Typical contents Architecture diagrams, technology choices, component communication Class diagrams, database schema, API contracts, algorithms
Who usually writes it Architects, senior engineers, tech leads Engineers who will actually implement the component
Audience Cross-team, leadership, other architects The engineers building that specific component
Real-world analogy An architect's master plan for a house An electrician's detailed wiring plan for one room
Common tools/notations Architecture diagrams, C4 model diagrams UML class diagrams and sequence diagrams (a formally defined notation maintained by the Object Management Group)
Mistake if skipped Components get built that don't actually fit together, as in the story above Engineers build the wrong internal structure, leading to messy, hard-to-maintain code

A simple way to remember it: HLD is about boxes and arrows between systems. LLD is about the actual contents of one box.

Full Example: Designing a URL Shortener

Let's make this completely concrete with one of the most common system design interview questions: building a URL shortener, like the kind that turns a long link into something short and shareable.

The High-Level Design

At a high level, we need: a way for a user to submit a long URL and get back a short one, a way for anyone to visit the short URL and get redirected to the original and a system that can handle a large number of both operations without slowing down.

                             User
                              |
                              v
                       Load Balancer
                    (spreads out traffic)
                              |
                              v
                     Application Servers
                    (handles the request)
                       /       |       \
                      v        v        v
              +----------+ +--------+ +-----------+
              |  Cache   | |Database| | Analytics |
              | (Redis)  | |        | |  Service  |
              +----------+ +--------+ +-----------+
              fast lookups  the long   tracks click
              for popular   URL lives   counts per
              short links    here       short link

Key HLD decisions worth writing down explicitly:

  • Database choice: a key-value style database works well here, since lookups are simple given a short code, return the long URL, with no complex relationships needed.
  • Caching: popular short links get requested constantly, so a cache like Redis sitting in front of the database avoids hitting the database for the same lookup over and over.
  • Read-heavy system: far more people click short links than create new ones, so the design should be optimized for extremely fast reads.

The Low-Level Design

Now we zoom into the actual "Application Server" box and design its internals properly.

Database Schema:

Table: urls
- id (auto-increment primary key)
- short_code (unique string, e.g. "aZ9kP")
- long_url (the original, full URL)
- created_at (timestamp)
- expiry_date (timestamp, optional)
- click_count (integer, default 0)

API Contract:

POST /api/shorten
Request:  { "longUrl": "https://example.com/very/long/path" }
Response: { "shortUrl": "https://short.ly/aZ9kP" }

GET /aZ9kP
Response: HTTP 302 redirect → https://example.com/very/long/path

The Core Algorithm (Base62 Encoding):

One clean way to generate a short code is to take the database's own auto-increment ID and convert it into a short string using a larger set of characters than plain numbers this is called Base62 encoding, since it uses all 26 lowercase letters, all 26 uppercase letters and all 10 digits, giving 62 possible characters per position instead of just 10.

public class Base62Encoder {
    private static final String CHARSET =
        "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final int BASE = 62;
    public static String encode(long id) {
        if (id == 0) {
            return String.valueOf(CHARSET.charAt(0));
        }
        StringBuilder shortCode = new StringBuilder();
        while (id > 0) {
            int remainder = (int) (id % BASE);
            shortCode.append(CHARSET.charAt(remainder));
            id = id / BASE;
        }
        return shortCode.reverse().toString(); // digits were built in reverse order
    }
}

Why this works: a database ID like 125 becomes a short string like 21 (in this simplified character set), because Base62 packs far more information into each character position than plain decimal numbers do this is exactly the same idea as why hexadecimal numbers are shorter than decimal ones, just with a bigger set of 62 symbols instead of 16. Tracing it by hand: 125 % 62 = 1, so we take character at index 1 ("1") and reduce id to 2. Then 2 % 62 = 2, so we take the character at index 2 ("2") and id becomes 0, so we stop. We built "1" then "2" and since we built it back-to-front, reversing gives us "21" as the final short code.

This one example shows the entire relationship between HLD and LLD clearly: the HLD said "we need a fast way to generate and look up short codes." The LLD is where that turns into an actual algorithm, an actual database schema and actual API request and response shapes that an engineer can sit down and build today.

The Requirement-to-Design Translator

Here's a simple tool worth using on any real project, built directly from the mistake in my opening story: for every requirement, explicitly ask what it means at the HLD level and what it means at the LLD level, instead of letting one team assume the other has it covered.

Requirement HLD-Level Decision LLD-Level Decision
"Process events in the order they happen." Choose a message broker and partitioning strategy that preserves order. Add a sequence number field to the event schema and reject or reorder out-of-sequence events in code.
"The system should be fast for readers." Add a caching layer between the app server and database. Decide the exact cache key format and the cache expiry (TTL) logic.
"Support millions of users." Decide between a monolith and microservices and plan horizontal scaling. Make sure database queries use proper indexes and avoid expensive operations per request.
"Keep user data secure." Decide where encryption happens at the load balancer, the app layer or the database. Choose the specific hashing or encryption algorithm and library used in code.

If you can't fill in both columns for a requirement, that's exactly the kind of gap that caused the two-week integration failure in my story a requirement that everyone nodded along to in a meeting, but that nobody translated into an actual decision at either level.

The Building Blocks of HLD

These are the pieces you'll see in almost every real High-Level Design, worth knowing by name:

  • Load Balancer : distributes incoming traffic across multiple servers so no single server gets overwhelmed.
  • API Gateway : a single entry point that routes requests to the right internal service and often handles authentication and rate limiting.
  • Application Servers : the actual servers running your business logic.
  • Database : where your data is stored, whether relational (like PostgreSQL) or non-relational (like MongoDB or Cassandra), chosen based on the shape of your data and how you need to query it.
  • Cache : a fast, temporary storage layer (like Redis) that avoids repeatedly hitting the database for the same data.
  • Message Queue : a system like Kafka or RabbitMQ that lets services communicate asynchronously, without waiting on each other directly.
  • CDN (Content Delivery Network) : servers spread across different locations that deliver content (like images or videos) from a location close to the user, reducing load time.
  • Monolith vs Microservices : a monolith is one large application containing all functionality, while microservices split functionality into independent, separately deployable services each with real trade-offs around simplicity versus scalability and team independence.

The Building Blocks of LLD

These are the pieces you'll see in almost every real Low-Level Design:

  • Class Diagrams : showing the actual classes in your system, their fields, their methods and how they relate to each other, using UML notation (the Unified Modeling Language, a standardized visual notation maintained by the Object Management Group).
  • Sequence Diagrams : showing the exact order of calls between objects or services for a specific action, like "what happens, step by step, when a user places an order."
  • Database Schema : the actual tables, columns, data types and relationships (primary keys, foreign keys) your system will use.
  • API Contracts : the exact request and response formats for every endpoint, including error responses.
  • Design Patterns : proven, reusable solutions to common design problems, like the Factory pattern for creating objects, the Observer pattern for notifying multiple parts of a system when something changes or the Strategy pattern for swapping out an algorithm at runtime. These come from the well-known "Gang of Four" design patterns catalog, one of the most referenced resources in object-oriented software design.
  • SOLID Principles : five widely taught object-oriented design principles (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation and Dependency Inversion), first articulated by Robert C. Martin, that guide how individual classes should be structured to stay maintainable as a system grows.

The 5-Question Design Audit

Before any project moves from planning into building, run these five questions the same ones that would have caught the mistake in my opening story before it cost us two weeks:

  • Boundaries: Have we clearly agreed on which component owns which responsibility, so two teams don't build overlapping or conflicting logic?
  • Contracts: Has every connection between components every API, every event schema been written down and agreed on by both sides, not just assumed?
  • Ordering and consistency: Have we explicitly decided whether order matters and if so, which layer (the message broker, the database or the application code) is responsible for enforcing it?
  • Failure handling: Have we discussed what happens when a component is slow, unavailable or returns bad data not just the happy path?
  • Scale: Have we written down real numbers expected users, requests per second, data volume rather than a vague "it should scale"?

If any answer is "we assumed the other team handled that," stop and write it down properly before writing more code that exact sentence is almost word-for-word what happened in my story.

Why This Matters in System Design Interviews

System design interviews are structured almost exactly around this HLD-to-LLD progression and knowing this structure removes a huge amount of interview anxiety. A strong candidate typically starts by clarifying requirements, then draws the High-Level Design the boxes and arrows, the major components and technology choices and only after that's agreed upon, zooms into one or two components for a Low-Level Design, discussing classes, schema or specific algorithms.

Interviewers are watching for exactly the gap described in this article: candidates who jump straight into deep implementation details of one component without ever stepping back to confirm the overall architecture makes sense or candidates who stay so high-level and vague that they never demonstrate they can actually build any of it. The strongest answers move deliberately between both levels, out loud, the same way a real architecture discussion should.

Common Mistakes People Make

  • Jumping straight into low-level details (classes, schemas, code) without agreeing on the high-level architecture first exactly the mistake that cost my team two weeks.
  • Staying so high-level that nothing is actually buildable, leaving engineers to individually guess at the missing details, often differently from each other.
  • Assuming another team or component "just handles" something like ordering guarantees or error handling without writing it down anywhere as an explicit decision.
  • Treating HLD and LLD as a one-time, upfront-only exercise, instead of revisiting and updating both as real constraints are discovered during building.
  • Skipping diagrams entirely and trying to describe a design only in prose, which makes it far harder for a team to spot missing pieces or mismatched assumptions at a glance.
  • Confusing "detailed" with "Low-Level Design." A very detailed paragraph about business rules is not the same as an actual class diagram or database schema LLD needs to be concrete enough to code directly from.

Frequently Asked Questions (FAQ)

1.What is the difference between High-Level Design and Low-Level Design?

High-Level Design describes the overall architecture the major components and how they connect. Low-Level Design describes the detailed internals of one specific component its classes, database schema and API contracts.

2.Do I need to create both HLD and LLD for every project?

For small personal projects, a lightweight version of both is still useful. For real, team-based projects, skipping either one as shown in the story that opens this article tends to cause integration problems or messy, hard-to-maintain code later.

3.Is UML required for Low-Level Design?

Not strictly required, but UML (Unified Modeling Language) is a widely recognized, standardized notation for class and sequence diagrams and using it makes your LLD easier for other engineers to understand quickly.

4.What are the SOLID principles and how do they relate to LLD?

SOLID is a set of five object-oriented design principles Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation and Dependency Inversion that guide how individual classes should be structured. They're commonly applied while creating a Low-Level Design to keep the resulting code maintainable.

5.Who is responsible for High-Level Design in a real company?

Usually architects, tech leads or senior engineers, though in smaller teams, the same engineers who write the Low-Level Design and code often participate in shaping the High-Level Design too.

6.Is System Design only useful for interviews?

No, while it's a well-known interview topic, the actual practice of planning architecture before building is exactly what prevents real production issues, like the two-week integration failure described in this article.

7.What's a good first system design problem to practice?

A URL shortener, like the one worked through in Section 6, is one of the most common starting points, since it touches databases, caching and a real algorithm, without being overwhelming in scope.

8.How detailed should a Low-Level Design be?

Detailed enough that an engineer could sit down and start writing code directly from it meaning actual class names, method signatures, database columns and API request/response shapes, not just a general description.

9.Can High-Level Design change after Low-Level Design has started?

Yes and it often should. Real constraints discovered while working through the details of an LLD sometimes reveal that a High-Level Design decision needs revisiting good teams treat this as normal, not as a failure of the original plan.

Key Takeaways

  • System Design is planning a software system's structure before building it, the same way a building is planned before construction begins.
  • High-Level Design is the big picture major components, how they connect and key technology choices.
  • Low-Level Design is the detailed, buildable plan for one specific component classes, schema, API contracts and algorithms.
  • Skipping the gap between the two assuming the other team "just handles it" is a real, costly mistake, not just a theoretical one, as shown in the story that opens this article.
  • A simple audit boundaries, contracts, ordering, failure handling and scale catches most of these gaps in minutes, long before they become expensive problems.

Related Articles

Responses (0)

Write a response

CommentHide Comments

No Comments yet.