Back to React
React
easy
mid

What is prop drilling in React and how do you avoid it?

Passing props through multiple intermediate components that don't use them, just to reach a deep descendant. It makes code verbose, tightly couples components, and is fragile to refactor. Fixes: Context, composition (children/slots), or a state library — pick by how the data is used.

4 min read·~6 min to think through

Prop drilling is passing data through layers of components that don't actually need it, purely to get it to a deeply nested component that does.

The problem

jsx
<App user={user}>
  <Layout user={user}>            {/* Layout doesn't use user */}
    <Sidebar user={user}>         {/* Sidebar doesn't use user */}
      <Profile user={user} />     {/* finally — Profile uses it */}

Layout and Sidebar are just pass-through couriers. The deeper the tree, the worse it gets.

Why it's bad

  • Verbose & noisy — every intermediate component's props are cluttered with things it ignores.
  • Tight coupling — intermediate components now "know about" user even though they don't use it; they can't be reused or moved easily.
  • Fragile refactors — moving Profile or adding a layer means re-threading props through every level.
  • Hard to trace — where did this prop come from, 5 levels up?

Note: prop drilling one or two levels is fine — it's explicit and clear. It's only a smell when it's deep and many props.

The fixes — pick by how the data is used

1. Context — for data that's genuinely "global" to a subtree and used in many places: theme, current user, locale, auth. The provider sits high, consumers read directly via useContext — no threading. (Watch the re-render caveat.)

2. Component composition / children / slots — often the best fix and underused. Instead of Sidebar forwarding a prop, pass the rendered element down as children:

jsx
<Layout>
  <Sidebar>
    <Profile user={user} />   {/* user passed where it's created, not drilled */}
  </Sidebar>
</Layout>

Layout and Sidebar just render {children} — they never see user. This removes the coupling without Context's machinery.

3. A state library (Zustand/Redux/Jotai) — for complex, cross-cutting app state used widely.

Choosing

  • A couple of levels → just drill, it's fine.
  • Truly tree-global, read in many spots → Context.
  • The intermediate components are just structural wrappers → composition / children.
  • Complex shared client state → a store.

The framing

"Prop drilling is threading a prop through intermediate components that don't use it, just to reach a deep child. It makes those middle components verbose, tightly coupled to data they don't care about, and fragile to refactor. A level or two is fine; deep is the smell. The fixes depend on usage: Context for genuinely tree-global data like theme or auth; component composition — passing the element as children so wrappers never see the prop — when the intermediates are just structural; and a state library for complex shared state. Composition is the most underused fix."

Follow-up questions

  • When is prop drilling actually fine?
  • How does passing children avoid prop drilling?
  • When would you use Context vs composition vs a store?
  • What's the downside of solving everything with Context?

Common mistakes

  • Reaching for Context for everything, including data only one child needs.
  • Not knowing the composition/children fix.
  • Treating any prop passing as 'drilling' — a level or two is fine.
  • Drilling deeply instead of recognizing the smell.

Performance considerations

  • Prop drilling itself isn't a perf problem — but new prop references each render can defeat memoization in intermediates. Context's fix has its own caveat: all consumers re-render on value change.

Edge cases

  • A prop needed by two distant cousins — composition may not reach both.
  • Frequently-changing drilled data — Context re-render concerns.
  • Intermediate components that DO use part of the data.

Real-world examples

  • Threading the current user through Layout → Sidebar → Profile, solved with an auth Context.
  • Compound components using composition so wrappers don't forward props.

Senior engineer discussion

Seniors define it precisely, note shallow drilling is fine, and prescribe the fix by usage pattern — Context for tree-global, composition/children for structural wrappers (the underused one), a store for complex shared state.

Related questions