# Vue Provide Inject Patterns in Vue 3: A Complete Guide to Dependency Injection

> Master Vue provide inject patterns in Vue 3. Eliminate prop drilling and implement efficient dependency injection for reactive component trees. Learn the complete guide.

- Repository: [Vue/core](https://github.com/vuejs/core)
- Tags: deep-dive
- Published: 2026-02-16

---

**Vue 3's provide/inject API eliminates prop drilling by enabling ancestor components to expose values that any descendant can retrieve through a prototype-based lookup chain, creating a lightweight dependency injection system that preserves reactivity across component trees.**

The `vuejs/core` repository implements a sophisticated dependency injection mechanism that allows developers to share state and services between components without explicitly passing props through every intermediate layer. This pattern fundamentally changes how large Vue 3 applications manage cross-cutting concerns while maintaining clean component APIs.

## How Provide/Inject Works Under the Hood

### Prototype-Based Value Resolution

The core mechanism relies on JavaScript's prototype chain for efficient lookups. In [`packages/runtime-core/src/component.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/component.ts), each component instance creates a `provides` object that inherits from its parent's `provides` (lines 36-37). When `inject()` is called, it traverses this chain upward until it finds the requested key.

In [`packages/runtime-core/src/apiInject.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiInject.ts), the `provide()` function registers values on the current instance's `provides` object (lines 24-30), while `inject()` performs the lookup by checking the parent component's provides through the prototype chain.

## Key Benefits of Vue Provide Inject Patterns

### Eliminates Prop Drilling

Traditional Vue applications require passing props through every intermediate component to reach deeply nested children. The provide/inject pattern removes this boilerplate by allowing direct ancestor-to-descendant communication without intermediate components knowing about the data. Only the provider and consumer need to coordinate on the injection key.

### Hierarchical Scope with Automatic Fallback

The prototype-based implementation in [`packages/runtime-core/src/component.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/component.ts) creates a natural shadowing mechanism. If a child component provides the same key as an ancestor, descendants receive the child's value while still maintaining access to parent values through the prototype chain. This enables scoped overrides without breaking the injection chain or requiring explicit merging logic.

### Type Safety with InjectionKey

Vue 3 exports an `InjectionKey<T>` type from [`packages/runtime-core/src/apiInject.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiInject.ts). This symbol-based type allows TypeScript to infer the correct type when injecting, preventing runtime type mismatches and enabling IDE autocomplete support. Using symbols instead of strings also eliminates key collision risks across different libraries or application modules.

### Global Service Registration

The pattern extends beyond component trees. In [`packages/runtime-core/src/apiInject.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiInject.ts) (lines 64-70), `inject()` falls back to the current app's `provides` object. This allows global services to be registered once with `app.provide()` and accessed anywhere, including functional components outside the standard component hierarchy.

### SSR and Custom Element Support

The implementation supports server-side rendering through [`packages/server-renderer/src/renderToString.ts`](https://github.com/vuejs/core/blob/main/packages/server-renderer/src/renderToString.ts) (lines 81-84), which injects the SSR context via the same provide mechanism. Similarly, [`packages/runtime-dom/src/apiCustomElement.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-dom/src/apiCustomElement.ts) (lines 326-331) enables custom elements to participate in the provide/inject hierarchy, allowing web components to access Vue app-level dependencies.

## Practical Implementation Examples

### Basic Composition API Usage

```ts
// Provider.vue
import { provide, ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    provide('counter', count)
    return { count }
  }
}

```

```ts
// Consumer.vue
import { inject } from 'vue'

export default {
  setup() {
    const count = inject('counter')
    if (!count) {
      throw new Error('count not provided')
    }
    return { count }
  }
}

```

### Type-Safe Injection with Symbols

```ts
// keys.ts
import type { InjectionKey } from 'vue'

export const UserKey: InjectionKey<{ name: string; id: number }> = Symbol()

```

```ts
// Provider.vue
import { provide } from 'vue'
import { UserKey } from './keys'

provide(UserKey, { name: 'Alice', id: 1 })

```

```ts
// Consumer.vue
import { inject } from 'vue'
import { UserKey } from './keys'

const user = inject(UserKey)
// TypeScript infers: { name: string; id: number } | undefined

```

### Options API Integration

```ts
export default {
  data() {
    return { message: 'hello' }
  },
  provide() {
    // Function form allows access to `this`
    return {
      greeting: this.message
    }
  }
}

```

During initialization, Vue calls this function and registers each key, as implemented in [`packages/runtime-core/src/componentOptions.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/componentOptions.ts) (lines 702-708).

### Global App-Level Providers

```ts
// main.ts
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)
app.provide('apiClient', myAxiosInstance)
app.mount('#app')

```

```ts
// AnyComponent.vue
import { inject } from 'vue'

export default {
  setup() {
    const apiClient = inject('apiClient')
    // Use without importing or prop drilling
    return {}
  }
}

```

### SSR Context Injection

```ts
// server entry
import { renderToString } from '@vue/server-renderer'
import { createApp } from 'vue'

const app = createApp(App)
await renderToString(app, { url: req.url })

```

```ts
// Component.vue
import { inject } from 'vue'
import { ssrContextKey } from '@vue/server-renderer'

const ssrContext = inject(ssrContextKey)

```

The SSR context is automatically provided via `app.provide(ssrContextKey, context)` in [`packages/server-renderer/src/renderToString.ts`](https://github.com/vuejs/core/blob/main/packages/server-renderer/src/renderToString.ts) (lines 81-84).

## Summary

- **Vue provide inject patterns** eliminate prop drilling by enabling direct ancestor-to-descendant communication through a prototype-based lookup mechanism implemented in [`packages/runtime-core/src/apiInject.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiInject.ts).
- The hierarchical scope allows child components to override parent providers while maintaining access to ancestor values through JavaScript's prototype chain, as defined in [`packages/runtime-core/src/component.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/component.ts) (lines 36-37).
- **Type safety** is enforced through the `InjectionKey<T>` type, enabling compile-time type checking and IDE support for injected values.
- **Global services** can be registered at the application level using `app.provide()` and accessed anywhere via the fallback mechanism in [`packages/runtime-core/src/apiInject.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiInject.ts) (lines 64-70).
- The pattern extends to **server-side rendering** and **custom elements**, with the SSR context injected via [`packages/server-renderer/src/renderToString.ts`](https://github.com/vuejs/core/blob/main/packages/server-renderer/src/renderToString.ts) and custom elements participating through [`packages/runtime-dom/src/apiCustomElement.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-dom/src/apiCustomElement.ts) (lines 326-331).

## Frequently Asked Questions

### What is the difference between props and provide/inject in Vue 3?

Props create explicit parent-child contracts where data flows down through every intermediate component, requiring each layer to declare and forward the prop. Provide/inject establishes an implicit dependency injection system where only the provider and consumer need to know about the value, eliminating intermediate boilerplate while maintaining reactive connections through the prototype chain.

### Can provide/inject be used with the Options API?

Yes, the Options API supports provide/inject through the `provide` and `inject` component options. The `provide` option can be an object or a function that returns an object, allowing access to `this` when using the function form. The `inject` option accepts an array of strings or an object mapping for aliasing and default values, as processed in [`packages/runtime-core/src/componentOptions.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/componentOptions.ts) (lines 702-708).

### Is provide/inject reactive in Vue 3?

Provide/inject itself is not inherently reactive, but it preserves the reactivity of whatever value you provide. If you provide a `ref` or `reactive` object, the injected value remains the same reactive proxy, allowing descendants to react to changes. However, replacing the entire provided value requires calling `provide()` again with a new reference, as the injection establishes the connection during component initialization.

### How does provide/inject handle server-side rendering in Vue 3?

During SSR, Vue injects the server context using the same provide/inject mechanism via `app.provide(ssrContextKey, context)` in [`packages/server-renderer/src/renderToString.ts`](https://github.com/vuejs/core/blob/main/packages/server-renderer/src/renderToString.ts) (lines 81-84). This allows components to access request-specific data like headers, cookies, or the current URL by injecting the SSR context key, ensuring isomorphic behavior between client and server environments without conditional logic.