Skip to main content

What is "prop drilling"?

Definition

Prop drilling is the process where data (props) is passed down the component tree through several intermediate levels that don't use this data themselves, but simply "pass it further".


A simple example

Suppose you have the structure:

javascript
<App> └── <Parent> └── <Child> └── <Grandchild>

You want to pass data from App -> to Grandchild.

Without context (through props):

javascript
function Grandchild({ user }) { return <p>Hello, {user.name}!</p>; } function Child({ user }) { return <Grandchild user={user} />; } function Parent({ user }) { return <Child user={user} />; } export default function App() { const user = { name: "Tim" }; return <Parent user={user} />; }

Here Parent and Child don't use user at all, they simply pass it further.

This is prop drilling.


Why this is bad

ProblemWhat happens
Code noiseEvery intermediate component is forced to have extra props
Hard to maintainChanging the structure requires changing every level
Isolation decreasesComponents become dependent on data they don't use
Reusability drops"Dumb" components are forced to know about unnecessary props
Hard to readThe "chain" of props makes the app's logic harder to understand

Illustration

javascript
App ├── user (stored here) ↓ Parent ↓ Child ↓ Grandchild (uses it)

The whole tree is "drilled" with props from top to bottom - hence the term "drilling".


A more realistic example

javascript
<App> <Navbar /> <Sidebar /> <Main> <PostList> <PostCard user={user} /> </PostList> </Main> </App>

If user is only needed in PostCard, but has to be passed through Main and PostList, that's already prop drilling hell.


How to solve the prop drilling problem

1. React Context API

The most standard way to get rid of drilling is to create a "global data source".

javascript
import { createContext, useContext } from "react"; const UserContext = createContext(null); function Grandchild() { const user = useContext(UserContext); return <p>Hello, {user.name}!</p>; } function App() { const user = { name: "Tim" }; return ( <UserContext.Provider value={user}> <Grandchild /> </UserContext.Provider> ); }

Now Grandchild gets user directly from context, not through a chain of props.


2. State management (Redux, Zustand, Jotai, Recoil)

If there's a lot of data and it's needed in different parts of the app, it's better to move it into a global store:

javascript
// store.js (example with Zustand) import { create } from "zustand"; export const useUserStore = create(set => ({ user: { name: "Tim" }, setUser: (user) => set({ user }), })); // Grandchild.jsx import { useUserStore } from "./store"; function Grandchild() { const user = useUserStore(state => state.user); return <p>Hello, {user.name}!</p>; }

Now there's no need to "drill" props - data is accessible from any component.


3. Custom hooks

If context or Zustand feel like "heavy artillery", you can simply make a custom hook to hide the passing:

javascript
function useUser() { const [user, setUser] = useState({ name: "Tim" }); return { user, setUser }; } function App() { const userStore = useUser(); return <Parent userStore={userStore} />; } function Grandchild({ userStore }) { const { user } = userStore; return <p>{user.name}</p>; }

Cleaner than passing every individual prop, but prop drilling remains - just simplified.


4. Composition instead of props

Sometimes you can pass components directly through children:

javascript
function Layout({ header, footer }) { return ( <div> <header>{header}</header> <main>Content</main> <footer>{footer}</footer> </div> ); } function App() { return ( <Layout header={<Header user={{ name: "Tim" }} />} footer={<Footer />} /> ); }

This doesn't remove prop drilling globally, but it makes data passing local and more manageable.


When prop drilling is acceptable

You don't always need to avoid it at any cost.

If the component tree is shallow (1-2 levels). If the prop is only needed a bit lower. If there isn't much data and it rarely changes.

Context and a store are needed when the problem is systemic, not occasional.


Summary

CriterionProp drilling
What it isPassing props through a chain of intermediate components
Why it's badPollutes the code, reduces isolation and reusability
When it's acceptableFor shallow and simple cases
How to solve itContext API, Zustand, Redux, custom hooks
Main rule"If a prop passes through more than 2 levels, think about context"

Main idea:

Prop drilling is when data is drilled through unnecessary components. The solution is to move the data source higher up and give direct access to it.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.