Props Drilling
Concept
A value being passed down through several layers that never use it, because the place that needs it sits far below the place holding it.
Why it exists
Splitting a screen into components — reusable units of code that make up an interface — is the basic move in frontend work, and values travel by a parent handing them to a child. The handed-down values are called props.
The trouble starts when the place holding a value drifts far from the place using it. Pagedeck's document list worked out that way. Information about the logged-in user is fetched once at the outermost layer, and where it's actually used is the author line inside a document card. Between them sit four layers — the list frame, the list, the card, the card header — and not one of them uses the user information. They receive it and pass it down.
The cost of that structure showed up when Theo wanted a profile photo next to the author name. Adding one line to a screen meant editing six files, because each of the four intermediate layers needed a new prop declared, the passing code updated, and the type declaration adjusted. None of those four layers displays the photo.
Props drilling is the name for this condition. It isn't a defect but a symptom of a structure growing, and having a name for it means a code review can say what needs changing in one word.
How it works
The cause is the rule that values only flow downward. A parent hands a value to a child, and a child can't reach up and take one. The rule itself is a benefit: trace any value on screen upward and it leads to exactly one origin, and there's exactly one place where it changes.
What pays the cost is the layers in between. A value crossing four layers means four places receiving it and passing it on, and every additional value repeats that work four more times.
The symptom appears in three forms.
- Components end up holding values they don't use. The list frame receives user information and renders none of it, yet it has to know the value's name and type anyway. Anyone reading that file also can't tell whether the value matters there.
- Reusing a part elsewhere gets harder. Move the card to another screen and that screen also has to feed user information down from the top. A part that was split out for reuse is now tied to one screen's structure.
- The same type declaration scatters across files. With TypeScript the same shape gets written at every layer, so when the shape changes there are that many more places to fix.
There's no fixed depth at which this becomes a problem. What teams use in practice is two conditions together: more than four layers, and intermediate layers that don't use the value. Two layers is often better left as it is, because the code itself shows where the value goes.
Where it shows up
The phrase comes up most often in a code review — a colleague reading the change before it merges. When a diff that adds one value also touches five unrelated files, this is the name that gets used, and both sides know immediately what is meant. It's shorthand precise enough to end the discussion.
The second place is scoping a refactoring, the work of improving structure while behavior stays the same. When choosing what to touch, paths carrying this symptom come first. There are three remedies, reached for in order of cost.
- Recompose. Build the part that uses the value where the value already lives, and hand the whole thing down; the intermediate layers hold a slot without knowing what fills it. It needs no new tooling, so it's the first thing to try.
- Open a channel to read from. A value placed once at the top can be read directly from anywhere beneath it. The intermediate layers disappear, and in exchange the part becomes tied to that channel. In a single app that trade is usually fine; in a shared component library it isn't.
- Bring in a state management tool, which gathers the values a screen has to remember into one place. It earns its keep from the point where several screens share the same value.
The third place is designing a new part. Anything meant for several screens is designed to receive less from the start. A card that takes an author line, rather than a card that takes user information, doesn't have to inherit a screen's structure when it moves.
How it sounds at work
"This is drilled four layers deep. Nothing in the middle uses it and they all take it."
Several layers that never touch the value are sitting in the path.
"One line added and six files changed."
The size of the diff doesn't match the size of the feature.
"Let's solve this by recomposing. It isn't a value that belongs in global state."
Fix the structure instead of introducing a tool.
Theo fixed the profile-photo problem by recomposing. Instead of sending user information down four layers, the author line got built outside the list and the card was changed to hold a slot for it. Every user-related prop in the three middle layers disappeared.
The next time a profile photo came up, the change touched one file: the author line component. The same request went from two days to thirty minutes, and that difference became the argument for the refactoring.
What people get wrong
The most common belief is that props drilling always has to be eliminated. The name sounds like a defect, so the conclusion follows easily. But passing a value down one or two layers is normal, and easier to read — where the value came from and where it goes is written in the code. Try to eliminate it by lifting every value to the top so anything can read it and the opposite problem appears: you can't find where a value on screen was changed, and moving one part to another project drags the channel along with it.
The second is expecting a tool to make it disappear. Adding a state management library looks like it should end prop passing, but the tool only handles values several screens share. Whether a card is expanded, what someone typed into a field — those belong inside the part, and they still travel from parent to child. The question worth asking is whether more than one screen needs the value at all. Code that passes props is supposed to remain after the tool arrives. A project that put every value into the tool ends up having to open the whole value list to change a single screen.
Easily confused with
| Term | What it covers | How it differs |
|---|---|---|
| State management | Where the values a screen remembers live and how they change | It's the name of an approach; props drilling is the name of a symptom. Choosing an approach that centralizes values reduces the symptom, but values kept inside a part still travel as props |
Where to go next
Last updated 2026-09-16