Tutorials Logic, IN info@tutorialslogic.com

Vue Plugins Create Install Plugins

Plugin Scope

A Vue plugin installs an application-wide capability through app.use. Its install function can provide a service, register global components or directives, or configure a carefully chosen global property.

Use a plugin for shared startup infrastructure or a distributed library. Keep feature logic in composables and ordinary imports so dependencies remain visible.

Plugin Boundary

A plugin is an object with install(app, options) or the install function itself. Vue passes the current application and app.use options, and installs the same plugin only once per application instance.

The plugin should own one capability and expose the smallest useful contract. It should not become a container for unrelated page state.

Need Prefer Why
Reusable helper Module or composable No application installation is needed.
Application service Plugin plus app.provide Consumers inject an explicit dependency.
Universal component or directive Plugin registration One startup registration is intentional.
Template convenience Local import first Global properties hide dependencies.

Install Contract

Validate required options before mounting. A Symbol-based InjectionKey prevents key collisions and gives TypeScript consumers an accurate service type.

  • Create mutable service state during installation, especially for SSR.
  • Document every component, directive, provider, and global property installed.
  • Use app.config.globalProperties sparingly; provide and inject usually make ownership clearer.

Typed Analytics Plugin

Typed Analytics Plugin
import type { InjectionKey, Plugin } from "vue";

interface Analytics {
  track(event: string): void;
}

export const analyticsKey: InjectionKey<Analytics> =
  Symbol("analytics");

export const analyticsPlugin: Plugin<
  [{ endpoint: string }]
> = {
  install(app, options) {
    if (!options.endpoint.startsWith("https://")) {
      throw new Error("HTTPS endpoint required.");
    }

    app.provide(analyticsKey, {
      track(event) {
        navigator.sendBeacon(
          options.endpoint,
          JSON.stringify({ event })
        );
      }
    });
  }
};

The plugin validates configuration once and provides a narrow typed service instead of exposing mutable options globally.

Install Before Mount

Install Before Mount
const app = createApp(App);

app.use(analyticsPlugin, {
  endpoint: "https://events.example.test/collect"
});

app.mount("#app");

Every descendant can inject the service during setup because installation happens before mount.

Plugin Consumers

Wrap inject in a composable that rejects a missing provider. Components then receive one typed entry point and a useful error when startup forgot to install the plugin.

Typed Consumer Composable

Typed Consumer Composable
export function useAnalytics(): Analytics {
  const analytics = inject(analyticsKey);

  if (!analytics) {
    throw new Error("Analytics plugin is not installed.");
  }

  return analytics;
}

The composable centralizes the injection key and missing-provider check.

Testing and SSR

Test consumers with a fake provider and test installation separately. This keeps network effects out of component tests.

For SSR, create a fresh application and plugin-owned service for every request. Mutable module state can leak data between requests.

  • Provide a test double through the mount global.provide option.
  • Keep install-time effects deterministic and reversible at application unmount when needed.
  • Do not store request-specific identity, locale, or permissions in a shared module singleton.

Plugin Decisions

Question Good signal
Is the capability used across the app? Plugin scope may be justified.
Can a direct import express it? Prefer the direct import.
Does each SSR request need its own value? Create it inside install.
Can a component test replace it? Expose a narrow injectable contract.
Before you move on

Plugin Review

6 checks
  • The capability genuinely belongs at application scope.
  • Options are validated during installation.
  • Consumers inject a narrow typed service.
  • Global registrations are documented and intentional.
  • Tests replace external effects with a provider double.
  • SSR state is request-local.

Plugin Contract Failures

  • Installed after mount

    Call app.use before app.mount.
  • Untyped global property

    Prefer an InjectionKey and composable unless the property is truly universal.
  • SSR state leaks

    Create mutable state per application installation.

Try this next

Build a Vue Plugin

0 of 2 completed

  1. Build a typed plugin that exposes isEnabled(name) through provide and inject. Validate and freeze the initial flag map.
  2. Mount a component with a fake provider and test enabled and disabled paths. Do not install the production plugin in this unit test.

Plugin Questions

When setup belongs to the whole application or a reusable library, not one feature component.

Prefer provide for an explicit injectable contract. Use globalProperties only for a truly universal instance property.

Vue prevents the same plugin object from being installed more than once on one application instance.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.