LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 2014 min read

Provide / Inject

Share data across many levels of nested components without passing props through every intermediate layer.

The Prop Drilling Problem

When a deeply nested component needs data from a far-off ancestor, passing it down as a prop through every intermediate component — none of which actually use it — is called prop drilling. It clutters components with props they only forward, never use.

provide()

An ancestor component calls provide() with a key and a value, making that value available to every descendant, no matter how deeply nested.

<!-- App.vue -->
<script setup>
import { provide } from 'vue';
provide('theme', 'dark');
</script>

inject()

Any descendant component calls inject() with the same key to retrieve that value — regardless of how many layers of components sit in between.

<!-- DeeplyNestedButton.vue -->
<script setup>
import { inject } from 'vue';
const theme = inject('theme', 'light'); // 'light' is the fallback if not provided
</script>
<template>
<button :class="theme">Click me</button>
</template>

Making Provided Data Reactive

Provide a ref (or reactive object) — not a plain value — if descendants should see updates when the source changes.

<script setup>
import { ref, provide } from 'vue';
const theme = ref('dark');
provide('theme', theme); // descendants see updates when theme.value changes
function toggleTheme() {
theme.value = theme.value === 'dark' ? 'light' : 'dark';
}
</script>
Provide/Inject Isn't a Global State Replacement

For state genuinely shared across unrelated parts of an app (not just an ancestor-descendant relationship), Pinia — covered in a later lesson — is the standard, more scalable tool. Reserve provide/inject for avoiding prop drilling within one component subtree.

Common Beginner Mistakes

Providing a plain value expecting it to update reactively

A plain string or number provided directly is a frozen snapshot — provide a ref if descendants need to see later changes.

Using provide/inject for data unrelated to the ancestor tree

This makes data flow harder to trace — reach for Pinia when the data isn't naturally scoped to a specific component subtree.

FAQs

It returns undefined, unless you pass a default value as inject()'s second argument — always provide a sensible default for optional dependencies.

Yes — provide/inject follows the component tree, so a closer provide() shadows one further up, exactly like nested scopes.

Summary

provide/inject solves prop drilling for data scoped to a component subtree, without needing a full state management library. With components covered, the next section moves into the Composition API itself in depth.

Next Lesson →

Introduction to the Composition API