Your team maintains a large Vue 3 Options API codebase; how do you decide whether to migrate it to the Composition API?
answer
- not deprecated, so no forced move
- where does the pain actually live?
- new code versus old code
- setup() as the bridge
- a compile-time flag for bundle size
basics
~20 sMigrate only where it pays: the Options API is not deprecated, so convert components whose concerns are tangled, whose mixins leak or whose typing hurts, write new code with the Composition API, and bridge with setup() meanwhile.
solid answer
~40 sStart from the fact that the Options API is **not deprecated**: nothing forces a rewrite, and a big-bang conversion carries risk for no user-visible gain. Look for where the style actually costs you: large components with several interleaved concerns, mixins whose sources and collisions are hard to trace, and TypeScript friction around `this`. Convert those, starting with the logic that is reused, by turning it into composables that options components can adopt through a `setup()` option. Write new components with `<script setup>`. Leave small, stable options components alone. Only if every component, including dependencies, stops using options can the `__VUE_OPTIONS_API__` compile-time flag be set to `false` to shrink the bundle, and that is a bonus, not a reason.
code
js · 16 lines// Stage 3: an existing options component adopts a composable extracted from a mixin
import { usePagination } from './usePagination'
export default {
props: { items: Array },
setup(props) {
const { page, pageCount, next, prev } = usePagination(() => props.items.length, 20)
return { page, pageCount, next, prev }
},
computed: {
visible() {
const start = (this.page - 1) * 20
return this.items.slice(start, start + 20)
}
}
}go deeper
Recall that the Options API is still supported in Vue 3 and that both styles can coexist in one app.
Explain how composables can be adopted by options components through setup(), and which pains the Composition API addresses.
Plan a staged migration: prioritise hotspots and shared logic, protect with behaviour tests, and keep features from being split across styles.
Justify the investment against its payoff, set exit criteria, and treat the bundle flag as a late optimisation gated on dependencies.
## Start from what is not forcing you The Vue team has said there is no plan to deprecate the Options API, calls it an integral part of Vue, and describes it as a solid choice for many low-to-medium-complexity scenarios. A Vue 3 codebase written with options is therefore **supported code**, not technical debt by definition. The question is not "when do we have to move?" but "where does moving pay for itself?" ## Where the Options API actually costs you The Composition API's documented advantages map onto three kinds of pain. Look for them in the codebase: 1. **Tangled concerns.** Components of several hundred lines where one feature's code is spread across `data`, `computed`, `methods` and `watch`. Every change needs scrolling between options, and extracting the feature is hard. 2. **Mixins.** Properties of unclear origin, name collisions between mixins, and mixins that depend on each other through shared names. 3. **TypeScript friction.** Heavy annotation, `PropType` everywhere, computed return types added to break circular inference, and weak types on mixins and injected values. Components that show none of these, such as small presentational ones or stable forms that rarely change, gain little from conversion. ## A staged approach | Stage | What happens | Why | |---|---|---| | 1. Convention | new components use `<script setup>` | stops the options surface growing | | 2. Reusable logic | mixins and duplicated logic become composables | fixes the worst maintainability problems first | | 3. Bridge | options components adopt composables via a `setup()` option | lets old and new code share logic immediately | | 4. Hotspots | convert large, frequently changed components | spend effort where developers feel it | | 5. Leave the rest | small, stable options components stay | conversion risk without payoff | Each stage ships on its own; there is no flag day. Reviews keep a feature on one side of the bridge rather than half in `data()` and half in `setup()`. ## Costs to put against the benefits - **Regression risk.** Conversion touches working code. Tests around behaviour, not implementation, are the safety net; components without them are poor early candidates. - **Team skill.** The Composition API expects a working understanding of reactivity, such as `.value`, refs versus reactive objects and cleanup of effects, and it removes the guard rails that options provide. Budget for learning and for agreed code-organisation conventions. - **Churn.** Large mechanical diffs make history harder to read and can collide with feature work. ## The bundle-size flag Vue exposes a compile-time flag, `__VUE_OPTIONS_API__`, which defaults to `true`. Setting it to `false` drops Options API support from the build and makes the bundle smaller, but the docs warn it also affects Vue components in your dependencies that rely on the Options API. It only becomes available once the whole application, libraries included, has stopped using options, so it is a late bonus rather than a reason to migrate. ## Signals that the migration is working - Reused logic lives in composables with explicit inputs and outputs. - The number of mixins goes down, not up. - TypeScript annotations in converted components shrink. - Changes to hotspot components touch fewer places per feature. ## Signals to stop If the remaining options components are small, stable and rarely touched, the conversion has done its job. Mixed codebases are normal; a style convention for new code plus composables for shared logic captures most of the value.
- When can a team set __VUE_OPTIONS_API__ to false, and what does it risk?Only when no component in the build uses the Options API, including those in third-party dependencies. The flag removes Options API support from Vue to shrink the bundle; a dependency that still relies on options would break. It is an end-state optimisation, not a migration driver.
- Which components should be converted first?Those where the style hurts most and tests exist: large, frequently changed components with interleaved concerns, and the mixins everything depends on. Extracting shared logic into composables first gives both old and new components the benefit, via the `setup()` option in the old ones.
saying these in an interview costs you the question
- The Options API is deprecated, so every component must be rewritten soon.
- A migration should convert all components in one release to avoid a mixed codebase.
- Setting __VUE_OPTIONS_API__ to false is safe as soon as your own code is converted.
- Converting a component to the Composition API makes it render faster by itself.
- Small, stable options components are the best place to start converting.