Designing an elevator system: the low-level design interview, explained
"Design an elevator system" is one of the hardest-feeling low-level design interview prompts, because the domain hides a scheduling problem inside a modelling problem. It is easy to name a car and a button; it is much harder to say which car answers a call on the seventh floor when two are already moving, and to structure your classes so that logic lives somewhere clean instead of in a tangle of if statements. The round is not testing whether you know how a lift works — it is testing object-oriented design: can you model cars, requests and controllers as classes, decide where the scheduling decision lives, and keep the design open when the interviewer adds a second car or a maintenance mode?
This guide walks the elevator the way a strong candidate works it in an LLD / OOD interview: clarify the requirements, identify the core entities, sketch the classes and the key methods, and then defend the decisions the interviewer always pushes on — how requests are scheduled, which car gets assigned, how a car's state is managed, and what happens when a dozen buttons are pressed at once. In a low-level design round you write these classes out in an editor, not as a finished program but as a design you can explain and extend out loud, one method at a time.
Why the elevator system comes up in low-level design interviews
The elevator earns its place because it forces two things an LLD round loves at once: a clean object model and a decision about behaviour. There are obvious entities (a system, cars, requests, buttons, doors) and obvious state (a car is moving up, idle, or out of service), but the interesting part is that the scheduling decision has nowhere obvious to live — and watching where you put it tells the interviewer how you think about responsibility and coupling.
The interviewer rarely lets a tidy class diagram stand on its own. "You have two elevators. A passenger on floor 7 presses 'up'. Car A is on floor 2 heading up to floor 10; car B is on floor 9 heading down to floor 1. Walk me through exactly which car your controller assigns, where that decision lives in your classes, and what happens if both cars are already full." That question — the dispatch decision and where it lives — is the one a pretty diagram can never survive, and the one the elevator is really testing once the basics are on the board.
The rounds on Zynter are modelled on how the loop runs, not scraped from any candidate's recall. What matters for prep is the shape: you put a class on the board, and the next sentence out of the interviewer's mouth adds a requirement or attacks a seam — a second car, a maintenance mode, a request that arrives while the car is already moving, or ten buttons pressed at once.
What the interviewer is really testing
A low-level design answer is read on the same four dimensions as any design round. Problem solving — did you model the domain cleanly and put the scheduling logic somewhere sensible, or scatter it across the car and the button? Communication — can you justify why the dispatch decision belongs in a controller and not inside the Elevator? Technical execution — do you handle the real behaviour (a request arriving mid-travel, a car reversing direction only when its queue drains, concurrent presses), or only a single car going up? Time management — did you clarify and prioritise before coding, and spend your half hour on the controller and the car model rather than the button bezel? Reading this guide teaches the design; it does not teach you to defend it while someone adds "now one car is in maintenance" mid-sentence.
Step 1: Clarify the requirements
The biggest mistake in an LLD round is writing a class before asking a question. Spend the first two minutes scoping out loud — it is graded.
Functional requirements to confirm:
- A building has N floors and M elevator cars.
- Two kinds of request: an external (hall) call — a passenger on a floor presses up or down — and an internal (car) call — a passenger inside presses a destination floor.
- The system assigns a car to each external request and each car services its stops in a sensible order.
- Cars have doors that open and close, and a display showing the current floor and direction.
Non-functional / constraints to surface (this is where senior candidates separate themselves):
- Pluggable scheduling — the dispatch algorithm should be swappable (a simple one now, a smarter one later) without rewriting the cars.
- Concurrency — many buttons can be pressed at the same moment, so request queues must be updated safely.
- Scope boundaries — are we modelling weight limits, express elevators, priority for VIP floors, or power-saving idle parking? Agree what is in and out, out loud.
State your assumptions explicitly: "I'll assume a fixed set of floors, cars that each serve all floors, and scheduling I'll keep behind an interface so we can start with a simple rule — tell me if you want express cars or weight limits in scope." That sentence shows you prioritise, which is itself part of the score.
Step 2: Identify the core entities
With requirements agreed, name the classes before writing any. The nouns are your first draft of the object model:
-
ElevatorSystem— the top-level object (often a singleton); owns the cars and the controller and is the entry point for requests. -
ElevatorController— holds the dispatch logic: given a request, decide which car serves it. This is where the scheduling decision lives, deliberately not inside a car. -
Elevator(orCar) — knows its current floor, direction and state, holds its own set of pending stops (often two direction-sorted queues), and moves one step at a time. -
Request— an external hall call (floor + desired direction) or an internal car call (destination floor). -
Button/Panel— the hall panel on each floor and the car panel inside; pressing one creates aRequest. -
DoorandDisplay— a car's door state and its floor/direction indicator. - Enums:
Direction { UP, DOWN, IDLE },ElevatorState { MOVING, STOPPED, IDLE, MAINTENANCE },DoorState { OPEN, CLOSED }.
Naming the relationships out loud matters as much as the classes: an ElevatorSystem has one ElevatorController and has many Elevators; an Elevator has a Door, a Display and a set of pending Requests; the ElevatorController references the cars so it can choose between them. That "has-a" vocabulary is what an interviewer listens for.
Step 3: Sketch the classes
Now write the classes — as skeletons you can talk through, not a finished program. Lead with the enums and the request, then the car and the controller, because they carry the design decisions.
enum Direction { UP, DOWN, IDLE }
enum ElevatorState { MOVING, STOPPED, IDLE, MAINTENANCE }
class Request {
int floor; // source (hall call) or destination (car call)
Direction direction; // for hall calls; null for a car call
boolean internal; // car call vs hall call
}
class Elevator {
int id;
int currentFloor;
Direction direction = Direction.IDLE;
ElevatorState state = ElevatorState.IDLE;
// stops split by direction so a car finishes one way before reversing
TreeSet<Integer> upStops = new TreeSet<>();
TreeSet<Integer> downStops = new TreeSet<>(Collections.reverseOrder());
synchronized void addStop(int floor) {
if (floor > currentFloor) upStops.add(floor);
else if (floor < currentFloor) downStops.add(floor);
}
void step() { /* move one floor toward the next stop in `direction`,
open doors on arrival, reverse only when the queue drains */ }
}
interface SchedulingStrategy {
Elevator selectElevator(List<Elevator> cars, Request r);
}
class ElevatorController {
private List<Elevator> cars;
private SchedulingStrategy strategy; // FCFS, SCAN/LOOK, nearest-car...
void handleRequest(Request r) {
if (r.internal) { /* goes to the car the passenger is in */ return; }
Elevator car = strategy.selectElevator(cars, r); // the dispatch decision
car.addStop(r.floor);
}
}
Talk through the choices as you write them: the dispatch decision lives behind a SchedulingStrategy interface in the controller, so a smarter algorithm is a new class rather than an edit to Elevator; each car keeps two direction-sorted queues so it serves everything one way before reversing (the "elevator algorithm"); and addStop is synchronized because that queue is shared mutable state hit by concurrent button presses — which sets up the concurrency conversation.
Step 4: The design decisions interviewers probe
The diagram is the easy half. The follow-ups live in a handful of decisions, and having an answer ready for each is what the round rewards.
-
Scheduling algorithm — start simple and name the upgrade path. FCFS (serve requests in arrival order) is easy but makes the car bounce inefficiently between floors. The standard improvement is the SCAN / LOOK "elevator algorithm": keep moving in one direction serving every stop along the way, then reverse when there is nothing further ahead. Name FCFS first, then LOOK as the optimisation, and keep both behind the
SchedulingStrategyinterface. - Which car gets the request — the dispatch heuristic. A good default: prefer a car already moving toward the request floor in the same direction that will pass it; otherwise the nearest idle car; break ties by load or distance. The key is that this decision lives in the controller, not the car — the car knows how to move, the controller knows which car should.
-
The car as a state machine — model
ElevatorStatetransitions explicitly (IDLE → MOVING → STOPPED → IDLE, plus MAINTENANCE), using a State pattern if the transitions get complex, so illegal moves (opening doors while moving) are impossible by construction rather than guarded by scatteredifs. - Concurrency — simultaneous button presses — this is the follow-up from the opening scenario. Ten passengers press buttons in the same instant and the controller and cars receive requests concurrently. The fixes to name: make each car's queue updates thread-safe (synchronised or a concurrent collection), and have the controller enqueue requests to a thread-safe structure that a dispatch loop drains, so two requests can't corrupt a car's stop set. The insight to state: the stop queues are shared mutable state, so their updates must be atomic.
- Edge cases — a request for the current floor, a full car, a car entering maintenance mid-route (reassign its pending hall calls), and no car available (the request waits). You will not design all of them; naming them shows you see past the happy path.
Low-Level Design
LLD · Elevator System
Design the elevator and defend the dispatch decision out loud
Design patterns that fit the elevator system
You do not need to force patterns in, but naming the ones that fit — and why — is a strong signal in an OOD round.
-
Strategy — the scheduling algorithm. A
SchedulingStrategyinterface lets FCFS, SCAN and LOOK be swapped without touching the cars or controller plumbing. The cleanest, most reused pattern in this problem. -
State — the elevator's lifecycle. Modelling IDLE / MOVING / STOPPED / MAINTENANCE as states makes illegal transitions impossible and keeps behaviour out of
ifladders. - Observer — the displays and hall indicators subscribe to a car's state and update when its floor or direction changes, so the car does not need to know about every screen.
-
Singleton — the
ElevatorSystemis often a single shared instance per building; note the trade-off that a singleton must be thread-safe and can complicate testing.
Say it crisply: Strategy for scheduling is the one that pays off most; State keeps the car's transitions clean; Observer decouples the displays; Singleton models the single system but I'd keep it thread-safe and injectable for tests. Naming the trade-off, not just the pattern, is what reads as experience.
Low-Level Design
LLD · Core skills
Apply Strategy, State and Observer out loud
How to talk about a low-level design in an interview
The probes from every section rhyme. Master these five and you can defend any LLD, not just the elevator.
- "What are the core classes here?" → Name the nouns — ElevatorSystem, ElevatorController, Elevator, Request, Door, Display — and the relationships (has-a, references) before writing a line. (communication)
- "Where does the scheduling decision live?" → In the ElevatorController behind a SchedulingStrategy interface, not inside the Elevator — the car knows how to move, the controller knows which car should. (problem solving)
- "A hall call arrives and two cars could take it — which one?" → A car already heading toward the floor in the same direction, else the nearest idle car, breaking ties by distance or load — decided in the controller. (technical execution)
- "Ten buttons are pressed at once — what happens?" → The stop queues are shared mutable state, so updates are synchronised or use a concurrent collection, and the controller drains requests through a thread-safe structure. (technical execution)
- "One car goes into maintenance mid-route — now what?" → Transition it to MAINTENANCE so it takes no new calls, reassign its pending hall calls to other cars, and let internal calls complete or be handled per policy. (time management)
Each maps to a debrief dimension. Reading them teaches the answers; it does not teach you to deliver them while someone says "now add an express elevator" — that only comes from saying them out loud.
How to prepare: a short plan
You do not need to memorise one reference solution. You need the OOD process automatic, so any "design X" prompt becomes requirements → entities → classes → decisions.
- Day 1: Drill the process on the elevator — clarify, list entities, sketch classes with relationships — until you can get a clean diagram on the board in ten minutes.
- Day 2: Drill the decisions — FCFS vs SCAN/LOOK scheduling, the car-selection heuristic, the state machine, and the concurrency of simultaneous presses. These are where the follow-ups live.
- Day 3: Do it out loud, timed, with someone adding a requirement mid-answer (an express car, weight limits, a maintenance mode), then move to a second LLD (parking lot, vending machine) to prove the process transfers.
This explainer feeds the broader low-level design interview track — the elevator is a classic OOD problem, and the requirements → entities → classes → decisions process it teaches transfers directly to the parking lot, the vending machine and the rest.
Frequently asked questions
What is an elevator system low-level design interview actually testing?
It is testing object-oriented design, not an algorithm in isolation. The interviewer wants to see how you turn a familiar real-world system into a clean set of classes, where you put the scheduling decision, and whether your design stays open to change when a requirement is added — a second car, a maintenance mode, an express elevator. The elevator is a favourite because it hides a dispatch problem inside a modelling problem: naming a car and a button is easy, but deciding which car answers a call and structuring your classes so that logic has a clean home is where candidates are separated. Your entities, your use of interfaces for the scheduling strategy, your handling of concurrent requests, and your ability to justify each decision out loud are all being scored.
What are the main classes in an elevator system design?
A standard model has an ElevatorSystem as the top-level object (often a singleton) that owns an ElevatorController and several Elevator cars. The ElevatorController holds the dispatch logic — given a request, it decides which car serves it — deliberately kept out of the Elevator. Each Elevator knows its current floor, Direction and ElevatorState, holds its pending stops (commonly two direction-sorted queues), and has a Door and a Display. A Request represents either an external hall call (a floor plus a direction) or an internal car call (a destination floor), created when a Button on a hall or car Panel is pressed. The key is to state the relationships — the system has a controller and many cars, a car has a door and a queue of stops — not just list the classes.
How does an elevator decide which floors to serve first?
The simplest approach is first-come-first-served, serving requests in the order they arrive, but that makes a car bounce inefficiently between distant floors. The standard improvement is the SCAN or LOOK algorithm, often called the "elevator algorithm": the car keeps moving in one direction, serving every stop along the way, and only reverses when there are no more requests ahead of it in that direction. In an object model this is why each car keeps its stops in two direction-sorted structures — an ascending set for upward stops and a descending set for downward stops — so it drains one direction fully before switching. You should name first-come-first-served first, then present SCAN/LOOK as the optimisation, and keep both behind a scheduling-strategy interface so they are swappable.
Where should the scheduling logic live in an elevator design?
In the ElevatorController, behind a SchedulingStrategy interface — not inside the Elevator. This is one of the most important design decisions in the problem and a common follow-up. The reasoning is a clean separation of responsibility: an Elevator knows how to move itself and open its doors, but the decision of which car should answer a given hall call depends on the state of all the cars, which only the controller sees. Putting the dispatch heuristic behind a strategy interface means you can start with a simple nearest-car rule and later swap in a smarter one without changing the cars or the controller's plumbing — an application of the open/closed principle that interviewers specifically listen for.
How do you handle concurrency in an elevator system?
The concurrency comes from many buttons being pressed at the same moment, so requests arrive at the controller and the cars simultaneously. The core issue is that each car's set of pending stops is shared mutable state: if two requests modify it at once without protection, the stop set can be corrupted or a stop lost. The fixes are to make the car's queue updates thread-safe — either synchronising the addStop method or using a concurrent collection — and to have the controller accept incoming requests into a thread-safe structure that a single dispatch loop drains, so the assignment of requests to cars is serialised. Naming the shared state explicitly and making its updates atomic is exactly the kind of signal the round rewards.
How do I practise a low-level design interview out loud?
Reading an elevator solution is not the same as defending your class boundaries while an interviewer asks which of two moving cars answers a call. On Zynter, the LLD track runs live voice rounds modelled on how real low-level design loops run — you write your classes and methods in the editor and a voice interviewer follows up one question at a time ("where does the dispatch decision live?", "two cars could take this call — which one?", "now one car is in maintenance"), then gives you a debrief on problem solving, communication, technical execution and time management. The score is a practice signal, not a hiring decision.
Practise it on Zynter
You can draw the class diagram. The round is won on defending which car answers the call out loud.
Pick the Elevator System low-level design round, write your classes in the editor, and defend them out loud to a voice interviewer that keeps asking "where does the scheduling decision live?" and "two cars could take this hall call — which one does your controller pick, and why?" — then read the debrief. Zynter.ai is on-demand mock interviews modelled on real company loops, with 150+ rounds across 20 companies including the low-level design track (Sep 2026).
Practise the Elevator System LLD round →
Browse all interview tracks




Top comments (0)