| |

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.

MethodPurpose
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
configAccess 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

MethodPurpose
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
configGlobal configuration

Configuration Options

OptionPurpose
config.errorHandlerHandle uncaught errors
config.warnHandlerHandle warnings
config.globalPropertiesAdd global properties
config.performanceEnable performance tracing
config.compilerOptionsConfigure the template compiler

Mounting

FormExample
CSS selectorapp.mount('#app')
DOM elementapp.mount(el)
With propscreateApp(App, props)
ReturnsRoot component instance

Multiple Instances

AspectBehavior
Global componentsPer instance
PluginsPer instance
providePer instance
PiniaPer createPinia() call
RouterPer router instance

Lifecycle

StepMethod
CreatecreateApp(Root)
Configureuse, component, provide
Mountmount(selector)
InteractVia DOM or instance
Teardownunmount()

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

PitfallWhy It HappensFix
Failed to mount appMount element not foundVerify the selector exists in the DOM
Plugin not registereduse called after mountRegister plugins before mounting
Global component not foundRegistered on a different instanceRegister on the correct instance
inject returns undefinedprovide not calledCall provide on the app instance
Memory leak in testsunmount not calledUnmount after each test
Multiple apps interferingShared plugin instancesCreate 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

ItemValue
CreationcreateApp(RootComponent)
PropscreateApp(Root, props)
Pluginapp.use(plugin)
Global componentapp.component(name, def)
Global directiveapp.directive(name, def)
Provideapp.provide(key, value)
Configapp.config
Mountapp.mount(selector)
Unmountapp.unmount()
IsolationEach instance is independent
ReturnsRoot component instance from mount

Key takeaways:

  • createApp returns 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 use method 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.provide makes a value available to every component. It is the application-level version of provide/inject, useful for values that the entire application needs.
  • app.config.errorHandler catches uncaught errors. It is the last line of defense for errors that escape component error handlers.
  • Multiple applications are supported. Each createApp call 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!