What are Vue 3's compile-time feature flags such as __VUE_OPTIONS_API__, which builds read them, and what happens if you never define them?
answer
- globals the bundler replaces
- esm-bundler builds only
- three flags, three defaults
- undefined falls back and warns
basics
~20 sThey are global constants the esm-bundler builds expect the bundler to replace so unused code can be tree-shaken: VUE_OPTIONS_API (default true), VUE_PROD_DEVTOOLS and VUE_PROD_HYDRATION_MISMATCH_DETAILS (both false). Left undefined, Vue applies the defaults and warns in development.
solid answer
~40 sVue's `esm-bundler` builds guard optional features behind identifiers the bundler should replace with literals via `define`/`DefinePlugin`: `__VUE_OPTIONS_API__` (default `true`), `__VUE_PROD_DEVTOOLS__` (default `false`) and `__VUE_PROD_HYDRATION_MISMATCH_DETAILS__` (default `false`, added in 3.4). Replaced with `false`, the guarded branch becomes dead code a minifier drops. The global, `esm-browser` and CommonJS builds hard-code these values, so the flags only matter for bundled apps. If a flag is left undefined, the renderer assigns its default on the global object when it is created and, in development, warns that the flags are not explicitly defined. The app works, but the unused code stays in the bundle. Setting the Options API flag to `false` breaks any component or library still written with the Options API.
code
ts · 12 linesimport { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
define: {
// values are substituted as source text
__VUE_OPTIONS_API__: 'false',
__VUE_PROD_DEVTOOLS__: 'false',
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'true'
}
})go deeper
Recall that these are bundler-replaced constants for the esm-bundler build, and that Vue still works when you leave them undefined.
Name the three flags and defaults, explain that undefined flags fall back with a dev warning, and why the non-bundler builds ignore them.
Decide when to enable production devtools or hydration mismatch details for debugging, and audit dependencies before compiling out the Options API.
Set a policy for production debugging features versus bundle discipline, and for whether a codebase commits to Composition-only components.
## What the flags are Vue 3's `esm-bundler` builds (`vue.runtime.esm-bundler.js` and `vue.esm-bundler.js`) contain code paths for features not every app uses. Instead of shipping them unconditionally, the source guards them with **compile-time feature flags**: global identifiers that your bundler is expected to replace with a literal `true` or `false`. Once replaced, a minifier sees `if (false) { ... }` and removes the dead branch. | Flag | Default | Controls | Since | |---|---|---|---| | `__VUE_OPTIONS_API__` | `true` | support for the Options API | 3.0 | | `__VUE_PROD_DEVTOOLS__` | `false` | devtools support in **production** builds | 3.0 | | `__VUE_PROD_HYDRATION_MISMATCH_DETAILS__` | `false` | detailed hydration-mismatch warnings in **production** | 3.4 | ## Which builds read them - **Only the `esm-bundler` builds.** They are the ones processed by your bundler, so only they can have identifiers substituted at build time. - The **global** (`vue.global.js`) and **`esm-browser`** builds, and the CommonJS server build, have the values **hard-coded** when Vue itself is built: Options API on, production devtools off, production mismatch details off. Setting the globals on a page using those files changes nothing. ## What happens if you never define them Vue still works. When the renderer is created (inside `createRenderer`, so that merely importing the runtime stays side-effect free), the `esm-bundler` build checks each flag. For any flag that is not a boolean it: 1. assigns the default to the global object (`__VUE_OPTIONS_API__ = true`, the other two `false`); 2. in development, logs one `console.warn` listing the undefined flags: *"Feature flags ... are not explicitly defined. You are running the esm-bundler build of Vue, which expects these compile-time feature flags to be globally injected via the bundler config in order to get better tree-shaking in the production bundle."* So an unconfigured build behaves as if the defaults were set, but the guarded code is still in the bundle because the minifier saw an identifier, not a constant. In practice many projects never see the warning: the Vue docs note that `@vitejs/plugin-vue` provides default values automatically, and Vue CLI provides some of them. ## Setting them You set them with the bundler's constant-replacement feature, for example Vite's `define` option or webpack's `DefinePlugin`. The values are substituted as source text, which is why the Vue docs show them as strings such as `'true'`. ## What each one changes at runtime - **`__VUE_OPTIONS_API__: false`** compiles out the code that applies Options API options during component setup. Components written with `data`, `methods`, `computed` or lifecycle options stop working, including any **third-party library** that still uses them. It is safe only when every component in the dependency tree uses `setup()` or `<script setup>`. - **`__VUE_PROD_DEVTOOLS__: true`** keeps the devtools integration in a production bundle so you can inspect a deployed app. Development builds always support devtools; this flag only concerns production, and it adds code, so it is meant for debugging. - **`__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: true`** makes a production SSR app log *which* node or attribute mismatched during hydration instead of a terse message. It helps chase a mismatch that only reproduces in production, again at the cost of extra code. ## Checking your own setup 1. Run a development build and look for the *Feature flags ... are not explicitly defined* warning in the console; if it is absent, your bundler plugin or config already defines them. 2. Search the bundler configuration for the three flag names to see which values are set explicitly and which rely on a plugin's defaults. 3. Before flipping `__VUE_OPTIONS_API__` to `false`, grep your dependencies for components that declare `data`, `methods` or lifecycle options, and test the production build, since that is where the removed code path shows up. 4. If you enable either production debugging flag to chase a problem, treat it as temporary and remove it once the issue is found. ## Interview pitfalls - The flags do not exist for the CDN builds; a question about them is a question about bundled apps. - Undefined is not the same as disabled: an undefined flag falls back to its default, it does not turn the feature off. - Turning off the Options API is a whole-dependency-tree decision, not a per-component one.
- Does defining __VUE_PROD_DEVTOOLS__ on a page that loads vue.global.prod.js enable devtools?No. The global, esm-browser and CommonJS builds have the flag values baked in when Vue is built, so a runtime global has no effect on them. Only the esm-bundler builds leave the identifiers for your bundler to replace, which is why the flags are a bundled-app concern.
- When is it safe to set __VUE_OPTIONS_API__ to false?Only when no component in the app or its dependencies relies on Options API options such as `data`, `methods` or lifecycle options, because the code that applies them is compiled out. An app written entirely in `<script setup>` can still break through a third-party component library that uses the Options API internally.
saying these in an interview costs you the question
- Thinks an undefined flag disables the feature it guards
- Sets the flags as runtime globals for a CDN global build
- Believes __VUE_PROD_DEVTOOLS__ is needed for devtools during development
- Turns off the Options API without checking third-party components
- Claims the hydration mismatch details flag exists in every Vue 3 release