Vue plugins are self-contained modules that add app-wide features to a Vue application. Popular tools like Vue Router, Pinia, and i18n libraries all ship as plugins installed via app.use().
A plugin can register global components, add custom directives, attach properties to app.config.globalProperties, or supply dependencies with app.provide(). Writing your own plugin keeps cross-cutting setup code clean and reusable across projects.
flowchart TD
Plugin["Plugin Object { install(app, options) }"] --> Use["app.use(plugin, options)"]
Use --> Components["Global Components and Directives"]
Use --> Provide["app.provide() Dependencies"]
A plugin is either an object exposing an install(app, options) method or an install function directly. Vue calls install once and passes the application instance plus any configuration options.
Here is a lightweight translation plugin in src/plugins/i18n.js that both provides an injection value and attaches a $t helper.
// src/plugins/i18n.js
export default {
install(app, options = {}) {
const dictionary = options.dictionary || {};
const translate = (key) => {
return (
key.split('.').reduce((acc, part) => (acc ? acc[part] : null), dictionary) ||
key
);
};
app.config.globalProperties.$t = translate;
app.provide('i18n', { translate });
}
};
Register the plugin in src/main.js before calling app.mount('#app').
// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import i18nPlugin from './plugins/i18n';
const app = createApp(App);
app.use(i18nPlugin, {
dictionary: {
greetings: {
welcome: 'Welcome to Vue 3!'
}
}
});
app.mount('#app');
Inside App.vue, templates can call $t, while <script setup> can inject i18n directly.
<script setup>
import { inject } from 'vue';
const { translate } = inject('i18n');
</script>
<template>
<section>
<h2>{{ $t('greetings.welcome') }}</h2>
<p>{{ translate('greetings.welcome') }}</p>
</section>
</template>
app.use() After app.mount(): Always register every plugin before app.mount('#app'). Calling app.use() afterward misses components that already mounted.globalProperties: Attaching too many helpers to app.config.globalProperties hides dependencies and weakens TypeScript inference. Prefer app.provide() paired with inject() inside <script setup>.options = {} inside install(app, options) so calling app.use(myPlugin) without arguments never throws a TypeError.app.use() is called twice with the same plugin?Vue tracks installed plugins on each app instance and ignores duplicate app.use(plugin) calls automatically.
this.$t inside <script setup>?No. <script setup> has no this context. Use app.provide() inside your plugin and inject() inside <script setup> instead.
Build a plugin when a library needs app-level setup once during startup, such as registering routes, global stores, or global components.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With