> ## Documentation Index
> Fetch the complete documentation index at: https://launchdarkly.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Vue SDK 2.x to 3.0 migration guide

<View title="Developer" />

<View title="Federal docs" />

<View title="EU docs" />

This topic explains the changes in the Vue SDK 3.0 release and how to adapt code that uses a 2.x version of the [Vue SDK](/docs/sdk/client-side/vue) to use version 3.0 or later.

**Version 3.0 includes several breaking changes**. The SDK moved from the standalone `launchdarkly-vue-client-sdk` package into the `js-core` monorepo as `@launchdarkly/vue-client-sdk`. It now builds on the same client-side platform as the [JavaScript SDK](/docs/sdk/client-side/javascript).

> [!TIP]
>
> **Read the JavaScript SDK 3.x to 4.0 migration guide too**
>
> Version 2.x of the Vue SDK wrapped version 3.x of the JavaScript SDK. Version 3.0 of the Vue SDK wraps `@launchdarkly/js-client-sdk`, which is the JavaScript SDK at version 4.0 and higher.
>
> The changes described in the [JavaScript SDK 3.x to 4.0 migration guide](/docs/sdk/client-side/javascript/migration-3-to-4.md) also apply to the Vue SDK. They include changes to `LDOptions`, flag change listeners, the `identify` method, and analytics events.

## Prerequisites

To complete this migration, you need the following:

* Vue version 3.3 or later
* The latest 2.x version of the Vue SDK installed in your application. To find it, visit [Vue SDK releases](https://github.com/launchdarkly/vue-client-sdk/releases) on GitHub.

Version 2.0 deprecated the `user` option, which version 3.0 removes. Your editor should flag instances of `user` in your code, so you can replace it with `context` before you begin migrating to 3.0.

## Supported Vue versions for Vue SDK v3.0

Version 3.0 of the Vue SDK requires Vue 3.3 or later. The reactive flag keys in version 3.0 use Vue's `toValue` function and the `MaybeRefOrGetter` type introduced in Vue 3.3. To learn more, read [Flag evaluation changes](#flag-evaluation-changes).

## Understanding what changed in version 3.0

There are several significant changes in version 3.0 of the Vue SDK:

* [Package name and location changes](#package-name-and-location-changes): The package is now `@launchdarkly/vue-client-sdk`, and several exported names changed.
* [Plugin and options changes](#plugin-and-options-changes): The Vue plugin is now `LDVuePlugin`, and you pass options to the underlying JavaScript SDK using an `ldOptions` property object. `LDPlugin` is still exported, but it is now an interface for plugins to LaunchDarkly clients and not a Vue plugin.
* [Context changes](#context-changes): The `context` option is now required, and version 3.0 removed the deprecated `user` option.
* [Client initialization changes](#client-initialization-changes): You create the client with the plugin or a provider component, rather than with `ldInit`.
* [Initialization status changes](#initialization-status-changes): `useInitializationStatus` reports the full initialization lifecycle, and replaces the boolean value that `useLDReady` returned.
* [Flag evaluation changes](#flag-evaluation-changes): Typed composables such as `useBoolVariation` replace the generic `useLDFlag` composable, and each one accepts a reactive flag key.
* [Client access changes](#client-access-changes): `useLDClient` returns an `LDVueClient` object, which adds methods for inspecting the initialization state and subscribing to context changes.
* [Support for multiple LaunchDarkly environments](#support-for-multiple-launchdarkly-environments): You can connect to more than one environment from the same application.
* [Removed APIs](#removed-apis): This section lists all parts of the version 2.x API that version 3.0 removes.

### Package name and location changes

In version 3.0 of the SDK, the package is named `@launchdarkly/vue-client-sdk`. To begin the migration, uninstall the 2.x package and install the 3.0 package:

```bash title="Uninstall v2.x" lines wrap theme={null}
npm uninstall launchdarkly-vue-client-sdk
```

```bash title="Install v3.0" lines wrap theme={null}
npm install @launchdarkly/vue-client-sdk
```

Next, update your import statements. Both the package name and several of the exported names changed:

```ts title="Vue SDK v2.x imports" lines wrap theme={null}
import { LDPlugin, useLDFlag } from 'launchdarkly-vue-client-sdk';
```

```ts title="Vue SDK v3.0 imports" lines wrap theme={null}
import { LDVuePlugin, useBoolVariation } from '@launchdarkly/vue-client-sdk';
```

### Plugin and options changes

In version 3.0 of the SDK, the plugin object and its options type are renamed. The options you pass through to the underlying JavaScript SDK move to a dedicated `ldOptions` property, so they no longer collide with Vue's own plugin options pattern.

Here are the renamed plugin exports and options:

<table>
  <thead>
    <tr>
      <th>Version 2.x</th>
      <th>Version 3.0</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>`LDPlugin`</td>
      <td>`LDVuePlugin`</td>
    </tr>

    <tr>
      <td>`LDPluginOptions`</td>
      <td>`LDVuePluginOptions`</td>
    </tr>

    <tr>
      <td>`options`, for JavaScript SDK configuration</td>
      <td>`ldOptions` property</td>
    </tr>

    <tr>
      <td>`streaming`, a top-level option</td>
      <td>`streaming`, inside `ldOptions`</td>
    </tr>
  </tbody>
</table>

Version 3.0 still exports the name `LDPlugin`, but it refers to a different type. In version 2.x, `LDPlugin` was the Vue plugin that you installed with `app.use()`. In version 3.0, `LDPlugin` is the interface for LaunchDarkly SDK plugins. These plugins extend the LaunchDarkly client rather than your Vue app. You pass these plugins to the underlying JavaScript SDK in the `plugins` field of `ldOptions`. If your version 2.x code imports `LDPlugin` to install the Vue plugin, change that import to `LDVuePlugin`.

In version 2.x, `clientSideID` was optional, because you could provide it later in a call to `ldInit`. Version 3.0 requires both `clientSideID` and `context` when you install the plugin or create a provider.

Here is a comparison of plugin registration in v2.x and v3.0:

```ts title="Vue SDK v2.x registration" lines wrap theme={null}
import { createApp } from 'vue';
import { LDPlugin } from 'launchdarkly-vue-client-sdk';
import App from './App.vue';

createApp(App)
  .use(LDPlugin, {
    clientSideID: 'example-client-side-id',
    context: { kind: 'user', key: 'example-user-key' },
    streaming: true,
  })
  .mount('#app');
```

```ts title="Vue SDK v3.0 registration" lines wrap theme={null}
import { createApp } from 'vue';
import { LDVuePlugin } from '@launchdarkly/vue-client-sdk';
import App from './App.vue';

createApp(App)
  .use(LDVuePlugin, {
    clientSideID: 'example-client-side-id',
    context: { kind: 'user', key: 'example-user-key' },
    ldOptions: { streaming: true },
  })
  .mount('#app');
```

### Context changes

In version 2.x, you could pass either a `context` or a deprecated `user` field to the plugin. If you passed both, `context` took precedence. If you omitted both, the SDK created an anonymous user context, `{ kind: 'user', anonymous: true }`, on your behalf.

Version 3.0 removes the deprecated `user` field, and requires you to provide `context` with `LDVuePluginOptions`, `createLDProvider`, and `createClient`. There is no implicit fallback to an anonymous context. To use an anonymous context, construct it explicitly:

```ts title="Vue SDK v2.x omitted context" lines wrap theme={null}
// Omitting both context and user created an anonymous context automatically.
app.use(LDPlugin, {
  clientSideID: 'example-client-side-id',
});
```

```ts title="Vue SDK v3.0 explicit anonymous context" lines wrap theme={null}
app.use(LDVuePlugin, {
  clientSideID: 'example-client-side-id',
  context: { kind: 'user', anonymous: true },
});
```

To learn more about contexts, read [Contexts](/docs/home/flags/contexts).

### Client initialization changes

In version 3.0 of the SDK, there are two ways to create the client and provide it to your components:

* `LDVuePlugin`, which you install with `app.use()`, provides the client to your entire app.
* `createLDProvider` returns a component that you render in your template. Unlike `LDVuePlugin`, the provider component supports `initializing` and `failed` slots. The slots enable you to gate rendering on the initialization state without calling a composable.

Both the plugin and the provider start the client immediately unless you pass `deferInitialization: true`. If you defer initialization, retrieve the client later with `useLDClient()` and call `client.start()` yourself.

Version 3.0 removes the version 2.x `ldInit()` composable and the `LD_INIT` injection key it relied on. A descendant component can no longer create the client, because the client always exists as soon as the plugin or provider runs.

Here is the new client initialization pattern:

```ts title="Vue SDK v2.x initialization" lines wrap theme={null}
import { createApp } from 'vue';
import { LDPlugin } from 'launchdarkly-vue-client-sdk';
import App from './App.vue';

createApp(App)
  .use(LDPlugin, {
    clientSideID: 'example-client-side-id',
    context: { kind: 'user', key: 'example-user-key' },
  })
  .mount('#app');
```

```ts title="Vue SDK v3.0 plugin initialization" lines wrap theme={null}
import { createApp } from 'vue';
import { LDVuePlugin } from '@launchdarkly/vue-client-sdk';
import App from './App.vue';

createApp(App)
  .use(LDVuePlugin, {
    clientSideID: 'example-client-side-id',
    context: { kind: 'user', key: 'example-user-key' },
  })
  .mount('#app');
```

```ts title="Vue SDK v3.0 provider initialization" lines wrap theme={null}
import { createApp, h } from 'vue';
import { createLDProvider } from '@launchdarkly/vue-client-sdk';
import App from './App.vue';

const LDProvider = createLDProvider('example-client-side-id', {
  kind: 'user',
  key: 'example-user-key',
});

createApp({
  render: () => h(LDProvider, null, { default: () => h(App) }),
}).mount('#app');
```

Here is how to gate rendering with the provider's slots:

```vue title="Vue SDK v3.0 gated rendering" lines wrap theme={null}
<template>
  <LDProvider>
    <template #initializing>Loading...</template>
    <template #failed="{ error }">Error: {{ error.message }}</template>
    <MyApp />
  </LDProvider>
</template>
```

Here is the new deferred initialization pattern:

```ts title="Vue SDK v2.x deferred initialization" lines wrap theme={null}
// main.ts
app.use(LDPlugin, { deferInitialization: true });

// In a component:
import { ldInit } from 'launchdarkly-vue-client-sdk';

const [isReady, client] = ldInit({
  clientSideID: 'example-client-side-id',
  context: { kind: 'user', key: 'example-user-key' },
});
```

```ts title="Vue SDK v3.0 deferred initialization" lines wrap theme={null}
// main.ts
app.use(LDVuePlugin, {
  clientSideID: 'example-client-side-id',
  context: { kind: 'user', key: 'example-user-key' },
  deferInitialization: true,
});

// In a component:
import { useLDClient } from '@launchdarkly/vue-client-sdk';

const client = useLDClient();
await client.start();
```

Version 3.0 also adds the `startOptions` and `bootstrap` options, which control the initialization timeout and bootstrap data at the plugin or provider level. If you set both `bootstrap` and `startOptions.bootstrap`, the top-level `bootstrap` value takes precedence. Here is an example:

```ts title="Vue SDK v3.0 startOptions and bootstrap" lines wrap theme={null}
app.use(LDVuePlugin, {
  clientSideID: 'example-client-side-id',
  context: { kind: 'user', key: 'example-user-key' },
  startOptions: { timeout: 5 },
  bootstrap: serverSideFlagValues,
});
```

For advanced patterns such as testing or multi-step bootstrapping, `createClient` and `createLDProviderWithClient` let you create and own the client instance separately from the provider component that renders it. When you use `createLDProviderWithClient`, you are responsible for calling `client.start()`. This pattern has no version 2.x equivalent. Here is an example:

```ts title="Vue SDK v3.0 client and provider ownership" lines wrap theme={null}
import { createClient, createLDProviderWithClient } from '@launchdarkly/vue-client-sdk';

const client = createClient('example-client-side-id', { kind: 'user', key: 'example-user-key' });
const LDProvider = createLDProviderWithClient(client);

await client.start({ timeout: 5 });
```

### Initialization status changes

In version 2.x, `useLDReady()` returned a `Readonly<Ref<boolean>>` object backed by the `LD_READY` injection key.

Version 3.0 removes both `useLDReady` and `LD_READY`. `useInitializationStatus()` now returns a `ComputedRef<InitializationStatus>` object. `InitializationStatus` is a discriminated union that covers the full initialization lifecycle, with a `status` of `'initializing'`, `'complete'`, `'timeout'`, or `'failed'`. If the status is `'failed'`, the object also includes an `error` field.

Here is how to read the initialization status:

```vue title="Vue SDK v2.x initialization status" lines wrap theme={null}
<script setup lang="ts">
import { useLDReady } from 'launchdarkly-vue-client-sdk';

const isReady = useLDReady();
</script>

<template>
  <div v-if="isReady">Ready</div>
  <div v-else>Loading...</div>
</template>
```

```vue title="Vue SDK v3.0 initialization status" lines wrap theme={null}
<script setup lang="ts">
import { useInitializationStatus } from '@launchdarkly/vue-client-sdk';

const status = useInitializationStatus();
</script>

<template>
  <div v-if="status.status === 'complete'">Ready</div>
  <div v-else-if="status.status === 'failed'">Error: {{ status.error.message }}</div>
  <div v-else>Loading...</div>
</template>
```

To replicate the version 2.x boolean, derive it with `computed`:

```ts title="Deriving v2.x boolean status in Vue SDK v3.0" lines wrap theme={null}
const status = useInitializationStatus();
const isReady = computed(() => status.value.status === 'complete');
```

### Flag evaluation changes

In version 2.x, the generic `useLDFlag<T>(key, defaultValue?)` composable, backed by the `LD_FLAG` injection key, evaluated any flag type using a type parameter.

Version 3.0 removes both `useLDFlag` and `LD_FLAG`. Flag evaluation now uses typed composables: `useBoolVariation`, `useStringVariation`, `useNumberVariation`, and `useJsonVariation`. Each composable accepts a flag key and a default value, and infers the return type from the composable name rather than from a type parameter. The default value is now required.

Here is the new flag evaluation pattern:

```vue title="Vue SDK v2.x flag evaluation" lines wrap theme={null}
<script setup lang="ts">
import { useLDFlag } from 'launchdarkly-vue-client-sdk';

const showBanner = useLDFlag<boolean>('show-banner', false);
const theme = useLDFlag<string>('ui-theme', 'default');
</script>
```

```vue title="Vue SDK v3.0 flag evaluation" lines wrap theme={null}
<script setup lang="ts">
import { useBoolVariation, useStringVariation } from '@launchdarkly/vue-client-sdk';

const showBanner = useBoolVariation('show-banner', false);
const theme = useStringVariation('ui-theme', 'default');
</script>
```

Each typed composable also has a `*VariationDetail` counterpart that returns the full evaluation detail, including the evaluation reason and the variation index. This has no version 2.x equivalent. Here is an example:

```ts title="Vue SDK v3.0 flag evaluation detail" lines wrap theme={null}
import { useBoolVariationDetail } from '@launchdarkly/vue-client-sdk';

const detail = useBoolVariationDetail('example-flag-key', false);
// detail.value.value          -> boolean
// detail.value.reason         -> LDEvaluationReason
// detail.value.variationIndex -> number | null
```

In version 3.0, every variation composable also accepts a reactive key, either a `Ref<string>` or a getter function. This means a component can change which flag it evaluates at runtime without unmounting. Here is an example:

```ts title="Vue SDK v3.0 runtime flag evaluation" lines wrap theme={null}
import { ref } from 'vue';
import { useBoolVariation } from '@launchdarkly/vue-client-sdk';

const flagKey = ref('example-flag-key');
const enabled = useBoolVariation(flagKey, false);

flagKey.value = 'another-flag-key'; // `enabled` re-evaluates automatically
```

### Client access changes

In version 2.x, `useLDClient()`, backed by the `LD_CLIENT` injection key, returned the base `LDClient` from the underlying JavaScript SDK.

Version 3.0 removes `LD_CLIENT`, and `useLDClient()` returns an `LDVueClient`. `LDVueClient` is a superset of `LDClient` that adds the `getInitializationState()`, `getInitializationError()`, `onContextChange()`, `onInitializationStatusChange()`, and `isReady()` methods. All of the existing `LDClient` methods are still available.

Here is how to access the client:

```ts title="Vue SDK v2.x LDClient" lines wrap theme={null}
import { useLDClient } from 'launchdarkly-vue-client-sdk';
import type { LDClient } from 'launchdarkly-vue-client-sdk';

const client: LDClient = useLDClient();
await client.identify({ kind: 'user', key: 'example-user-key' });
```

```ts title="Vue SDK v3.0 LDVueClient" lines wrap theme={null}
import { useLDClient } from '@launchdarkly/vue-client-sdk';
import type { LDVueClient } from '@launchdarkly/vue-client-sdk';

const client: LDVueClient = useLDClient();
await client.identify({ kind: 'user', key: 'example-user-key' });
```

### Support for multiple LaunchDarkly environments

Version 3.0 adds `createLDVueInstanceKey()`, which creates a Vue `InjectionKey`. You can pass the key to the `injectionKey` option on a plugin or provider, and to the optional `injectionKey` parameter on any composable. This lets you connect to more than one LaunchDarkly environment in the same application. This has no version 2.x equivalent.

Here is an example:

```ts title="Vue SDK v3.0 environment injectionKey" lines wrap theme={null}
import {
  createLDVueInstanceKey,
  createLDProvider,
  useBoolVariation,
} from '@launchdarkly/vue-client-sdk';

const experimentKey = createLDVueInstanceKey();

const ExperimentProvider = createLDProvider('example-client-side-id', context, {
  injectionKey: experimentKey,
});

// In a child component:
const inExperiment = useBoolVariation('example-flag-key', false, experimentKey);
```

If you nest providers that use the same injection key, the inner provider shadows the outer one for its descendants. To avoid this, create a separate injection key for each environment.

### Removed APIs

Version 3.0 removes the following APIs:

* The `LDPlugin` Vue plugin, replaced with `LDVuePlugin`. Version 3.0 still exports an `LDPlugin` type, but it is the interface for LaunchDarkly SDK plugins. To learn more, read [Plugin and options changes](#plugin-and-options-changes).
* `LDPluginOptions`, replaced with `LDVuePluginOptions`.
* `ldInit()`. The plugin and provider now create the client. To control when the client connects to LaunchDarkly, use `deferInitialization` and `client.start()`. To learn more, read [Client initialization changes](#client-initialization-changes).
* `useLDReady()`, replaced with `useInitializationStatus()`.
* `useLDFlag()`, replaced with the typed variation composables `useBoolVariation()`, `useStringVariation()`, `useNumberVariation()`, and `useJsonVariation()`.
* The `LD_INIT`, `LD_READY`, `LD_CLIENT`, and `LD_FLAG` injection keys. Composables now read from a single injection key, which you can override with `createLDVueInstanceKey()`. To learn more, read [Support for multiple LaunchDarkly environments](#support-for-multiple-launchdarkly-environments).
* The deprecated `user` option, replaced with the required `context` option.
* The top-level `streaming` option. Set `streaming` inside `ldOptions` instead.

## Updating your dependencies

`@launchdarkly/js-client-sdk` is a dependency of `@launchdarkly/vue-client-sdk`. You do not need to install or update it separately.

To learn more about the version 3.0 API, read the [Vue SDK reference](/docs/sdk/client-side/vue).
