# Vue 3 Composition API: Why and When

> I discuss what the Composition API brings over Options API in Vue 3, and when you should prefer it, with concrete examples.

- Published: 2020-07-05
- Category: Interface
- Tags: Vue.js
- Reading time: 3 min read
- Source: https://www.muhammetsafak.com.tr/en/blog/vue-3-composition-api-why-and-when/
- Language: en-US
- Author: Muhammet Şafak

---
I had been following the Vue 3 beta from a distance. When I saw the Composition API announcement, my first reaction was skepticism: is this just [React Hooks](/en/blog/how-react-hooks-changed-the-way-we-write-components/) for Vue? Why did they feel the need for this change?

Answering that question with real code turned out to be more useful than theorizing. A few weeks back I used the Vue 3 beta on a project. I ran both the new API and the old Options API side by side in the same codebase. Once I saw the difference firsthand, the answer to "why" became a lot clearer.

## Why Options API Has Its Limits

Options API is Vue 2's familiar face: `data`, `computed`, `methods`, `watch` — everything has its category. That structure is intuitive for small components. The problem surfaces when a component grows: logic belonging to a single feature gets scattered across four different blocks.

Consider a user search feature. The search query lives in `data`, the filtering logic in `computed`, the debounce timer back in `data`, and the reset action in `methods`. All four pieces belong to the same feature, yet they end up in four different places in the file.

```javascript
// Options API — search logic scattered across four sections
export default {
  data() {
    return {
      query: '',
      timer: null,
      results: [],
    };
  },
  computed: {
    filteredResults() {
      return this.results.filter(r => r.active);
    }
  },
  methods: {
    onInput(value) {
      clearTimeout(this.timer);
      this.timer = setTimeout(() => this.search(value), 300);
    },
    async search(query) {
      const { data } = await axios.get('/api/search', { params: { q: query } });
      this.results = data;
    },
    reset() {
      this.query = '';
      this.results = [];
    }
  }
};
```

## The Same Logic with Composition API

With Composition API you can keep that same logic together in a single `setup` function — or better yet, in a dedicated composable you can extract:

```javascript
// useSearch.js — as a standalone composable
import { ref, computed } from 'vue';
import axios from 'axios';

export function useSearch() {
  const query = ref('');
  const results = ref([]);
  let timer = null;

  const filteredResults = computed(() =>
    results.value.filter(r => r.active)
  );

  function onInput(value) {
    clearTimeout(timer);
    timer = setTimeout(() => search(value), 300);
  }

  async function search(q) {
    const { data } = await axios.get('/api/search', { params: { q } });
    results.value = data;
  }

  function reset() {
    query.value = '';
    results.value = [];
  }

  return { query, filteredResults, onInput, reset };
}
```

Using it in a component:

```javascript
import { useSearch } from '@/composables/useSearch';

export default {
  setup() {
    const { query, filteredResults, onInput, reset } = useSearch();
    return { query, filteredResults, onInput, reset };
  }
};
```

The search logic now lives in a single file, is portable, and is independently testable. When another component needs the same behavior, you just import `useSearch`.

## Comparison with Mixins

[In Vue 2](/en/blog/transitioning-to-component-based-ui-architecture-with-vue/), mixins filled the role that composables play today. But mixins have well-known problems: if two mixins define a property with the same name, it's unclear which one wins. You look at `this.results` and wonder — did the component define that, or did one of the mixins inject it? With composables, that ambiguity is gone. You name what `useSearch` returns yourself, and where it comes from is explicit.

This distinction seems trivial in small components. In a large component where four or five mixins are mixed together, that ambiguity becomes a real maintenance burden.

## When Composition API, When Options API?

Let me answer this directly:

**For small, self-contained components**, Options API is still perfectly readable. A few data fields, a few methods — the categorization is clarity, not overhead. Especially in Vue 2 codebases, migrating to Composition API unnecessarily just makes the code more complex.

**For reusable logic**, Composition API is a clear win. What you used to do with mixins in Vue 2 becomes far cleaner with composables — no name collisions, no properties of uncertain origin.

**For large components**, Composition API lets you group logic by feature rather than by type. That is a significant difference.

TypeScript compatibility is another compelling reason. Composition API works much better with TypeScript; type inference in Options API is limited by comparison.

## Migrating from Vue 2

Options API is not being removed in Vue 3 beta — both APIs can be used together. You don't have to migrate existing Vue 2 projects all at once. Using Composition API for new components while keeping Options API for existing ones is a sensible interim strategy.

---

Dismissing Composition API as "a feature added under React's influence" is unfair. It solves a real problem — logic scattered throughout a component — in a concrete and practical way. For someone with Vue 2 habits, picking up this API takes a few days; over the long haul, that investment pays off the moment you move beyond trivial components.
