skip to content

In a Vue 3 app, what does setting the __VUE_OPTIONS_API__ compile-time flag to false remove, and what can break?

level: middleimportance: nice to knowfreq 25%

answer

  1. esm-bundler build only
  2. default true
  3. data, methods, computed, watch, mixins
  4. props, emits, setup still work

basics

~20 s

VUE_OPTIONS_API set to false lets the bundler drop Options API support: data, computed, methods, watch, lifecycle options, mixins and extends. Components written with setup or script setup keep working; any dependency written with the Options API breaks.

solid answer

~40 s

`__VUE_OPTIONS_API__` is one of Vue 3's **compile-time feature flags**, honoured only by the ES module bundler build. It defaults to `true`. Setting it to `false` (with the bundler's `define`, e.g. Vite's `define` option) turns the runtime's Options API branches into dead code: options such as `data`, `computed`, `methods`, `watch`, lifecycle options like `mounted`, `provide`/`inject` options, and the merging of `mixins` and `extends`; `app.mixin` warns in development that mixins need Options API support, and `this.$watch` becomes a no-op. What **stays** is what `<script setup>` compiles to: `props`, `emits`, `setup` and `render`/`template`. The risk is dependencies: any library component written with `data()` or `methods` stops working, so audit them before flipping it.

go deeper

for a junior

Recall that Vue 3 can drop Options API support at build time with a flag, if the app uses only the Composition API.

for a middle

List what the flag removes and what stays, and why script setup components keep working.

for a senior

Audit dependencies and global mixins before disabling it, and verify with tests because failures are silent rather than build errors.

for a principal

Decide whether a Composition-only policy is worth enforcing across a codebase for the saving, given the constraint it puts on dependency choices.

## What the flag is Vue 3's source contains branches guarded by build-time constants. In the **ES module bundler build** (`vue.esm-bundler.js`, the one a bundler uses by default), those constants are left for your bundler to replace. `__VUE_OPTIONS_API__` is one of them: - Default: **`true`** — Options API support is included. - Set to **`false`** — every branch that implements the Options API becomes unreachable, and the bundler's minifier removes it. - It has no effect on the prebuilt global or browser builds; those are already compiled with a fixed choice. If the flags are not defined at all in a development build, Vue prints a warning starting "Feature flag __VUE_OPTIONS_API__ is not explicitly defined. You are running the esm-bundler build of Vue". Vite's Vue plugin supplies default values, and you change them with the bundler's `define` setting: ```ts // vite.config.ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], define: { __VUE_OPTIONS_API__: 'false' } }) ``` ## What goes and what stays | Feature | With the flag `false` | |---|---| | `data`, `computed`, `methods`, `watch` options | Removed — ignored at runtime | | Lifecycle options (`mounted`, `beforeUnmount`, ...) | Removed | | `provide` / `inject` as component options | Removed (the `provide()`/`inject()` functions still work) | | `mixins`, `extends`, `app.mixin` | Removed; `app.mixin` warns in development | | `this.$watch` | Becomes a no-op | | `props` and `emits` options | **Kept** | | `setup`, `render`, `template` | **Kept** | The split is not "object syntax versus `<script setup>`". `defineProps` and `defineEmits` compile to the `props` and `emits` options, and a `<script setup>` block compiles to `setup`, so those remain. What disappears is the machinery that reads the classic options and merges mixins. ## What can break 1. **Your own components** that still use `data`, `methods` or `mounted` — they render but lose their state and behaviour, often without an error. 2. **Third-party component libraries** written with the Options API — the most common surprise, since you do not see their source. 3. **Global mixins** installed by plugins — `app.mixin` stops applying them. 4. **Code relying on `this.$watch`** in plugins or components. The Vue docs warn about exactly this trade-off: smaller bundles, but possible incompatibility with libraries that rely on the Options API. ## How to adopt it safely - Confirm that every component you ship, including dependencies, is written with `setup` or `<script setup>`. - Search dependencies for `data()`, `methods:` and `mixins:` in their distributed files. - Flip the flag in a branch, run the full test suite and click through the app; silent failures are the risk, not build errors. - Compare production bundle sizes before and after, so the decision rests on your numbers rather than a general promise. ## Why the default is `true` Vue 3 supports both APIs, and much of the ecosystem — including many component libraries — is still written with the Options API. A default of `false` would break those libraries for anyone who did not know the flag existed. Keeping it `true` makes every app work out of the box; removing the code is an explicit, informed opt-in. ## How much it saves The Vue docs describe the result only as smaller bundles, without a figure, and the real saving depends on your build and minifier. Treat any number you have heard as a rumour: - Build the app twice, once with each value, and compare the entry chunk's compressed size. - Weigh that difference against the audit and the ongoing constraint on dependencies. - Record the decision, because a future dependency written with the Options API will break without warning. ## When it is worth it - A new application written entirely with the Composition API. - A widget or embed where every kilobyte counts. - Not an app mid-migration from Vue 2 style code, or one depending on Options API libraries — there the risk outweighs a modest saving.

  • With `__VUE_OPTIONS_API__` set to false, does a `<script setup>` component using `defineProps` still receive props?
    Yes. `defineProps` compiles to the component's `props` option, and props normalization stays in the runtime whatever the flag. What the flag removes is merging props declared through `mixins` or `extends`, together with the rest of the classic options machinery.
  • Why does the flag only work with the ES module bundler build of Vue?
    The flag is a placeholder the bundler replaces at build time; only the `esm-bundler` build leaves those placeholders in the code. The prebuilt browser and global builds were already compiled with fixed values, so there is nothing left for your build to replace.

saying these in an interview costs you the question

  • Thinks setting the flag to false also removes the props and emits options.
  • Believes it breaks <script setup> components.
  • Expects the flag to shrink a CDN global build of Vue.
  • Flips the flag without checking whether dependencies use the Options API.
  • Assumes Options API components throw a clear error when the flag is off.