Vue 3: A Beginner Guide to the Composition API, Pinia and Vapor Mode

Vue.js is a progressive JavaScript framework for building user interfaces and single-page applications. Evan You created it and released it in 2014. Vue 3 is the current major version, and as of this writing the latest stable release on GitHub is 3.5.x. This guide gets you from zero to a working Vue 3 app, using the modern Composition API with <script setup>.

What Is Vue 3?

Vue 3 is the current major version of the Vue.js framework. It adds the Composition API for organizing logic in reusable functions called composables, a faster reactivity system based on proxies, first-class TypeScript support and the <script setup> syntax for single-file components. Vue is progressive: you can drop it into one page or build a full application with routing and state management.

If you are comparing frameworks, see how Svelte 5 compares to React and what SolidJS does differently. For a convention-heavy alternative, read what Ember.js is.

Why Choose Vue.js?

  1. Gentle learning curve. Templates look like HTML, and you can start with a script tag.
  2. Fine-grained reactivity. Vue tracks which state each part of a template uses and updates only what changed.
  3. Component-based. Single-file components keep template, logic and styles together.
  4. Incrementally adoptable. Use it for one widget or the whole app.
  5. Official ecosystem. Vue Router for routing and Pinia for state management are maintained by the Vue team.
  6. Good documentation. The official docs at vuejs.org cover both API styles.

Getting Started

Create a project

The official way is create-vue, which sets up Vite for you:

bash
npm create vue@latest

It asks whether you want TypeScript, Vue Router, Pinia, Vitest and a linter, then scaffolds the project. Then:

bash
cd my-vue-app
npm install
npm run dev

Try it from a CDN

For a quick experiment on a plain HTML page:

html
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

Core Concepts

Reactive state with ref

In the Composition API you declare state with ref (for single values) or reactive (for objects). Inside <script setup>, anything you declare is available in the template.

vue
<script setup>
import { ref } from 'vue';

const count = ref(0);

function increment() {
  count.value++;
}
</script>

<template>
  <button @click="increment">Count: {{ count }}</button>
</template>

In templates, Vue unwraps refs automatically, so you write count, not count.value. In JavaScript you use .value.

Computed values and watchers

computed caches a derived value and recalculates only when its dependencies change. watch runs a side effect when a source changes.

vue
<script setup>
import { ref, computed, watch } from 'vue';

const message = ref('');
const isLong = computed(() => message.value.length > 5);

watch(message, (value) => {
  console.log('Message changed to', value);
});
</script>

<template>
  <input v-model="message" />
  <p v-if="isLong">Message is long enough</p>
</template>

Template directives

DirectivePurpose
v-bind (or :)Bind an attribute to state
v-modelTwo-way binding for form inputs
v-if, v-else, v-showConditional rendering
v-forRender a list
v-on (or @)Listen to events

Components, props and emits

Each .vue file is a component. Declare props and events with defineProps and defineEmits:

vue
<!-- Greeting.vue -->
<script setup>
const props = defineProps({
  name: String,
});
const emit = defineEmits(['greeted']);
</script>

<template>
  <h2 @click="emit('greeted')">Hello, {{ props.name }}!</h2>
</template>

Use it from a parent:

vue
<script setup>
import Greeting from './Greeting.vue';
</script>

<template>
  <Greeting name="Alex" @greeted="console.log('clicked')" />
</template>

Composables

A composable is a function that uses Vue's reactivity and returns state and helpers. It is the Composition API's answer to mixins.

javascript
// useCounter.js
import { ref } from 'vue';

export function useCounter(initial = 0) {
  const count = ref(initial);
  const increment = () => count.value++;
  return { count, increment };
}

Options API vs Composition API

Vue 3 supports both. The Options API (data, methods, computed) is still fully supported and fine for small components. The Composition API groups code by feature instead of by option type, which scales better and works better with TypeScript. New projects usually use <script setup>.

The Vue Ecosystem

Vue Router

The official router handles navigation, nested routes and route guards.

bash
npm install vue-router

Pinia

Pinia is the official state management library and the recommended choice for Vue 3. It replaced Vuex, which is now in maintenance mode.

bash
npm install pinia
javascript
// stores/counter.js
import { defineStore } from 'pinia';
import { ref } from 'vue';

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0);
  function increment() {
    count.value++;
  }
  return { count, increment };
});

If you are weighing state libraries across frameworks, my Zustand vs Redux comparison covers the React side.

TypeScript

Vue 3 is written in TypeScript. With <script setup lang="ts"> you get typed props through defineProps<{ name: string }>() and typed emits. Run type checks in your editor with Volar and in CI with vue-tsc. Note that Vue single-file component checking depends on tooling that embeds the TypeScript compiler, so check compatibility before moving a Vue project to TypeScript 7 (see TypeScript 7).

What Is Vapor Mode?

Vapor Mode is an experimental compilation strategy for Vue that compiles components to direct DOM operations instead of using the virtual DOM. It targets less runtime code and better performance while keeping the same component syntax. As of this writing, Vapor Mode is part of the Vue 3.6 line, which is in release-candidate pre-release on GitHub, while the latest stable release is 3.5.x. Treat it as opt-in and check the Vue release notes before using it in production.

Frequently Asked

What is Vue 3? The current major version of Vue.js, built around the Composition API, a proxy-based reactivity system and TypeScript support.

Should I use the Options API or the Composition API? The Composition API with <script setup> for new code. The Options API is still supported and fine for simple components.

Is Vuex still used? Existing projects use it, but Pinia is the official recommendation for Vue 3.

Is Vapor Mode stable? Not yet as of this writing. It ships with the Vue 3.6 line, which is still a release candidate, while the stable release is 3.5.x.

How do I create a Vue 3 project? Run npm create vue@latest and follow the prompts.

If you want to go deeper, the official documentation at vuejs.org is excellent.