Vue.js 3 🟢 Vue Application Instance Instantiation (createApp) and Mounting
Every Vue 3 application begins with createApp. The function takes a root component and returns an application instance, which is the object that holds the application’s configuration, plugins, and global state. The instance is not mounted yet; it exists independently until mount is called with a DOM selector. This separation between creating and mounting is deliberate, and it enables patterns that were awkward in Vue 2: registering plugins before mount, configuring global properties conditionally, and testing the application without attaching it to the document.
The application instance replaces the global Vue object from Vue 2. In Vue 2, plugins and global configuration were attached to the framework itself, which meant that two applications on the same page shared the same global state. In Vue 3, each createApp call produces an isolated instance, so multiple Vue applications can coexist on the same page without interfering with each other. This chapter covers the instance, its methods, the mounting process, the root component’s props, and the patterns that the instance enables.
Key point: createApp(RootComponent) creates an application instance. The instance provides use, component, directive, provide, config, and mount. Calling mount(selector) renders the root component into the selected DOM element. Each instance is isolated, so multiple Vue applications can coexist on the same page.
Why the application instance exists
The global state problem. In Vue 2, global configuration lived on the Vue constructor. Registering a component or plugin affected every Vue instance on the page. This made it impossible to have two applications with different configurations running side by side. Vue 3 moves the global API to the application instance, so each application is isolated.
The plugin problem. Plugins need to be registered before the application mounts, because they may add global components, directives, or properties that the root component uses. The instance provides the use method for this, and the separation of create and mount gives the application a chance to configure itself first.
The testing problem. Tests often need to create an application instance without attaching it to the DOM. The instance can be created, configured, and inspected without calling mount. When the test is ready, it mounts to a test element, and it can unmount when the test finishes.
The SSR problem. Server-side rendering creates an application instance, renders it to a string, and discards it. The same code that runs in the browser runs on the server, but the mount step is replaced by renderToString. The instance is the shared abstraction that makes this possible.
The multiple-applications problem. A page may have several independent Vue applications: a navigation bar, a chat widget, a dashboard panel. Each is created with its own createApp call, and each has its own configuration. They do not interfere because the instance is the boundary.
a. Creating the application instance
The createApp function takes a root component and returns the application instance.
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
The root component is the top of the component tree. Everything the application renders descends from it. The root component can be a single-file component, a component defined with defineComponent, or an options object.
import { createApp } from 'vue';
const App = {
template: `<h1>Hello, {{ name }}</h1>`,
data() {
return { name: 'Vue' };
},
};
const app = createApp(App);
The root component can also receive props, which are passed as the second argument to createApp:
const app = createApp(App, { userId: '42' });
The props are available in the root component through its props option or, in <script setup>, through defineProps.
b. The application instance methods
The instance exposes a set of methods that configure the application before it is mounted.
| Method | Purpose |
|---|---|
use(plugin, ...options) | Register a plugin |
component(name, definition) | Register a global component |
directive(name, definition) | Register a global directive |
provide(key, value) | Provide a value to all components |
config | Access global configuration |
mount(selector) | Mount the application |
unmount() | Unmount the application |
The use method registers a plugin:
import { createPinia } from 'pinia';
import router from './router';
app.use(createPinia());
app.use(router);
The component method registers a global component:
import BaseButton from './components/BaseButton.vue';
app.component('BaseButton', BaseButton);
The provide method makes a value available to every component in the application through inject:
app.provide('apiUrl', 'https://api.example.com');
The config object holds global configuration, such as the error handler and the warning handler:
app.config.errorHandler = (err, instance, info) => {
console.error('Global error:', err, info);
};
app.config.warnHandler = (msg, instance, trace) => {
console.warn('Warning:', msg, trace);
};
The config.globalProperties object adds properties that are available in every component’s template:
app.config.globalProperties.$formatDate = (date: Date) => date.toISOString();
Global properties are accessed through this in the options API. In the Composition API, they are less common because imports are explicit, but they are still available.
c. Mounting the application
The mount method renders the root component into the DOM element matching the selector.
app.mount('#app');
The selector can be a CSS selector string or an actual DOM element:
app.mount(document.getElementById('app')!);
The element is replaced by the root component’s rendered output. The innerHTML of the element is not used; Vue compiles the root component’s template and mounts the result. This is why the mount element is typically an empty <div>.
<div id="app"></div>
const app = createApp(App);
app.mount('#app');
If the mount element is not found, Vue throws an error. The element must exist in the DOM before mount is called. This is why the script tag is placed at the end of the <body> or loaded as a module, which defers execution until the DOM is parsed.
The mount method returns the root component instance:
const vm = app.mount('#app');
The returned instance is the public interface of the root component. It is used in tests and in code that needs to interact with the root component directly.
d. Unmounting the application
The unmount method removes the application from the DOM and cleans up its resources.
app.unmount();
After unmounting, all components are destroyed, all watchers and effects are stopped, and the DOM element is emptied. The application instance cannot be mounted again; a new instance must be created if the application needs to be re-created.
The unmount method is used in tests to clean up between test cases and in applications that need to tear down and recreate a Vue application dynamically.
// In a test
const app = createApp(Component);
app.mount(el);
// ... assertions ...
app.unmount();
e. Multiple application instances
Because each createApp call produces an isolated instance, multiple Vue applications can exist on the same page.
const navApp = createApp(NavBar);
navApp.component('Icon', Icon);
navApp.mount('#nav');
const chatApp = createApp(ChatWidget);
chatApp.use(createPinia());
chatApp.mount('#chat');
The two applications have separate configurations. The Icon component is registered only in navApp, and the Pinia store is registered only in chatApp. They do not share state, plugins, or global components.
This pattern is common in progressive enhancement, where each interactive region of the page is its own Vue application. It is also useful in micro-frontend architectures where each micro-frontend is an independent Vue application.
The one thing they may share is a plugin instance. If both applications need Pinia, each calls createPinia() separately to get an isolated store, or they share a single instance if the state is intentionally shared.
Complete Example Session
// ============================================
// PART 1: BASIC CREATEAPP
// ============================================
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.mount('#app');
// ============================================
// PART 2: CREATEAPP WITH PROPS
// ============================================
const app = createApp(App, { userId: '42' });
app.mount('#app');
// ============================================
// PART 3: REGISTER A PLUGIN
// ============================================
import { createPinia } from 'pinia';
import router from './router';
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount('#app');
// ============================================
// PART 4: REGISTER A GLOBAL COMPONENT
// ============================================
import BaseButton from './components/BaseButton.vue';
const app = createApp(App);
app.component('BaseButton', BaseButton);
app.mount('#app');
// ============================================
// PART 5: PROVIDE A VALUE
// ============================================
const app = createApp(App);
app.provide('apiUrl', 'https://api.example.com');
app.mount('#app');
// ============================================
// PART 6: GLOBAL ERROR HANDLER
// ============================================
const app = createApp(App);
app.config.errorHandler = (err, instance, info) => {
console.error('Error:', err, info);
};
app.mount('#app');
// ============================================
// PART 7: GLOBAL PROPERTY
// ============================================
const app = createApp(App);
app.config.globalProperties.$formatDate = (date: Date) =>
date.toISOString();
app.mount('#app');
// ============================================
// PART 8: MOUNT TO A DOM ELEMENT
// ============================================
const app = createApp(App);
const el = document.getElementById('app');
if (el) app.mount(el);
// ============================================
// PART 9: UNMOUNT
// ============================================
const app = createApp(App);
app.mount('#app');
// Later:
app.unmount();
// ============================================
// PART 10: MULTIPLE APPLICATIONS
// ============================================
const navApp = createApp(NavBar);
navApp.mount('#nav');
const chatApp = createApp(ChatWidget);
chatApp.use(createPinia());
chatApp.mount('#chat');
These ten parts cover the basic createApp, props, plugin registration, global components, provide, the global error handler, global properties, mounting to a DOM element, unmounting, and multiple applications.
Quick Reference
Instance Methods
| Method | Purpose |
|---|---|
use(plugin) | Register a plugin |
component(name, def) | Register a global component |
directive(name, def) | Register a global directive |
provide(key, value) | Provide a value |
mount(selector) | Mount to the DOM |
unmount() | Unmount from the DOM |
config | Global configuration |
Configuration Options
| Option | Purpose |
|---|---|
config.errorHandler | Handle uncaught errors |
config.warnHandler | Handle warnings |
config.globalProperties | Add global properties |
config.performance | Enable performance tracing |
config.compilerOptions | Configure the template compiler |
Mounting
| Form | Example |
|---|---|
| CSS selector | app.mount('#app') |
| DOM element | app.mount(el) |
| With props | createApp(App, props) |
| Returns | Root component instance |
Multiple Instances
| Aspect | Behavior |
|---|---|
| Global components | Per instance |
| Plugins | Per instance |
provide | Per instance |
| Pinia | Per createPinia() call |
| Router | Per router instance |
Lifecycle
| Step | Method |
|---|---|
| Create | createApp(Root) |
| Configure | use, component, provide |
| Mount | mount(selector) |
| Interact | Via DOM or instance |
| Teardown | unmount() |
Best Practices
✅ Do This:
// Create, configure, then mount
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount('#app');
// Use provide for application-wide values
app.provide('apiUrl', 'https://api.example.com');
// Set a global error handler
app.config.errorHandler = (err, instance, info) => { /* ... */ };
// Unmount in tests
app.unmount();
// Create separate instances for separate regions
const navApp = createApp(NavBar);
const chatApp = createApp(ChatWidget);
❌ Don’t Do This:
// Mount before configuring
app.mount('#app');
app.use(createPinia()); // ❌ plugin registered too late
// Rely on global state
// Vue 3 has no global Vue object // ❌ use the instance
// Forget to check the mount element
app.mount('#missing'); // ❌ throws if not found
// Share an instance across unrelated applications
// Each application should have its own instance // ❌
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
Failed to mount app | Mount element not found | Verify the selector exists in the DOM |
| Plugin not registered | use called after mount | Register plugins before mounting |
| Global component not found | Registered on a different instance | Register on the correct instance |
inject returns undefined | provide not called | Call provide on the app instance |
| Memory leak in tests | unmount not called | Unmount after each test |
| Multiple apps interfering | Shared plugin instances | Create a new plugin per application |
Real-World Examples
1. Standard Bootstrap
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount('#app');
2. Application with Props
const app = createApp(App, { userId: '42' });
app.mount('#app');
3. Global Component
app.component('BaseButton', BaseButton);
4. Provide Value
app.provide('apiUrl', 'https://api.example.com');
5. Error Handler
app.config.errorHandler = (err, instance, info) => {
console.error(err, info);
};
6. Global Property
app.config.globalProperties.$formatDate = (d: Date) => d.toISOString();
7. Mount to Element
const el = document.getElementById('app');
if (el) app.mount(el);
8. Unmount
app.unmount();
9. Multiple Applications
const navApp = createApp(NavBar);
navApp.mount('#nav');
const chatApp = createApp(ChatWidget);
chatApp.mount('#chat');
10. Plugin with Options
app.use(MyPlugin, { option1: true });
Visual
Application Lifecycle
┌──────────────────────────────────────────────────────────────┐
│ 1. createApp(RootComponent) │
│ └── Returns the application instance │
│ │
│ 2. Configure the instance │
│ ├── app.use(plugin) │
│ ├── app.component(name, def) │
│ ├── app.provide(key, value) │
│ └── app.config.errorHandler = fn │
│ │
│ 3. app.mount(selector) │
│ └── Renders the root component into the DOM │
│ │
│ 4. app.unmount() │
│ └── Removes the application and cleans up │
└──────────────────────────────────────────────────────────────┘
Multiple Applications
┌──────────────────────────────────────────────────────────────┐
│ HTML page │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ <div id="nav"> │ │
│ │ └── navApp = createApp(NavBar) │ │
│ │ ├── app.component('Icon', Icon) │ │
│ │ └── app.mount('#nav') │ │
│ └────────────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ <div id="chat"> │ │
│ │ └── chatApp = createApp(ChatWidget) │ │
│ │ ├── app.use(createPinia()) │ │
│ │ └── app.mount('#chat') │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Each application is isolated. │
└──────────────────────────────────────────────────────────────┘
The Instance as a Boundary
┌──────────────────────────────────────────────────────────────┐
│ app.config.globalProperties │
│ app.component('BaseButton', ...) │
│ app.directive('focus', ...) │
│ app.provide('apiUrl', ...) │
│ app.use(router) │
│ app.use(pinia) │
│ │ │
│ ▼ │
│ app.mount('#app') │
│ └── Everything below this line sees the configuration │
│ │
│ A second createApp call creates a separate boundary. │
└──────────────────────────────────────────────────────────────┘
Mount and Unmount
┌──────────────────────────────────────────────────────────────┐
│ BEFORE MOUNT: │
│ <div id="app"></div> │
│ │
│ AFTER app.mount('#app'): │
│ <div id="app"> │
│ <h1>Hello</h1> │
│ <button>Click</button> │
│ </div> │
│ │
│ AFTER app.unmount(): │
│ <div id="app"></div> │
└──────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Creation | createApp(RootComponent) |
| Props | createApp(Root, props) |
| Plugin | app.use(plugin) |
| Global component | app.component(name, def) |
| Global directive | app.directive(name, def) |
| Provide | app.provide(key, value) |
| Config | app.config |
| Mount | app.mount(selector) |
| Unmount | app.unmount() |
| Isolation | Each instance is independent |
| Returns | Root component instance from mount |
Key takeaways:
createAppreturns an isolated application instance. Global configuration, plugins, components, and provides are attached to the instance, not to the framework. Two applications on the same page do not share state.- Plugins must be registered before mount. The
usemethod adds a plugin to the instance, and the plugin’s effects are applied when the application mounts. Registering a plugin after mount has no effect. app.mount(selector)renders the root component into the DOM. The mount element is replaced by the rendered output. If the element does not exist, Vue throws an error.app.unmount()tears the application down. It destroys components, stops watchers, and empties the DOM. The instance cannot be mounted again; a new instance is required.app.providemakes a value available to every component. It is the application-level version ofprovide/inject, useful for values that the entire application needs.app.config.errorHandlercatches uncaught errors. It is the last line of defense for errors that escape component error handlers.- Multiple applications are supported. Each
createAppcall produces a separate instance with its own configuration. This is the pattern for progressive enhancement and micro-frontends.
Remember: The application instance is the root of every Vue 3 application. It is created with createApp, configured with use, component, directive, provide, and config, and mounted with mount. The separation between creation and mounting is what allows the application to be configured before it renders, and it is what allows multiple applications to coexist on the same page. The instance replaced the global Vue object from Vue 2, and the change is significant: global state is now per-application, which makes the framework suitable for incremental adoption, micro-frontends, and testing. Understanding the instance is understanding how a Vue 3 application begins.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!