provide & inject — Dependency Injection

Skip Prop Drilling Across Deep Trees

provide & inject — Dependency Injection

provide makes a value available to every descendant component; inject reads it. Useful for cross-cutting concerns without prop drilling.

5 min read Level 3/5 #vue#provide#inject
What you'll learn
  • Provide a value from an ancestor
  • Inject by key (use a Symbol for type safety)
  • Type provides with InjectionKey

provide and inject are Vue’s built-in dependency-injection mechanism. An ancestor provides a value under a key; any descendant can inject it without passing props down through every layer.

The Basic Pattern

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

<template>
  <ThemedPanel />
</template>
<!-- DeepChild.vue -->
<script setup>
import { inject } from 'vue'
const theme = inject('theme', 'light')  // 'light' is the default
</script>

<template>
  <p>Current theme: {{ theme }}</p>
</template>

Because theme is a ref, descendants automatically re-render when it changes.

Type-Safe Keys With InjectionKey

String keys are fragile — typos crash silently. Use a Symbol typed as InjectionKey<T> to get full TypeScript inference.

// keys.ts
import type { InjectionKey, Ref } from 'vue'
export const ThemeKey: InjectionKey<Ref<string>> = Symbol('theme')
// provider
import { provide, ref } from 'vue'
import { ThemeKey } from './keys'

const theme = ref('dark')
provide(ThemeKey, theme)
// consumer
import { inject } from 'vue'
import { ThemeKey } from './keys'

const theme = inject(ThemeKey)  // typed as Ref<string> | undefined

App-Level Provide

You can provide values from the app instance — every component sees them.

// main.ts
app.provide('apiUrl', 'https://api.example.com')

When to Reach For It

  • Theming, i18n locale, current user — values needed everywhere.
  • Plugin APIs that don’t fit cleanly as props.

Use props for normal parent-child data — provide/inject creates implicit coupling. For app-wide reactive state, prefer a Pinia store.

ref vs reactive — Which to Pick →