# Vue Core — Admin & Architecture Guide

This guide is for the people who build, ship, and contribute to **Vue itself** — maintainers, contributors, framework integrators, and architects who need to understand how the `vuejs/core` monorepo is structured, how it builds, and how its internals actually work. It is written from the source at version **3.5.35**, commit `86ad076`.

If you are *using* Vue to build an application, read the User Guide instead. This document assumes you are working *on* Vue or integrating its packages at a deep level.

---

## 1. Executive Summary

`vuejs/core` is a **pnpm monorepo** that produces the `vue` npm package and a family of `@vue/*` packages. The codebase is written in TypeScript, built with **Rollup + esbuild**, tested with **Vitest**, and organized so that each layer of the framework — reactivity, runtime, compiler, server renderer — is an independently publishable package with a clear dependency direction.

| Property | Value |
|---|---|
| Repository | `vuejs/core` (the Vue 3 core) |
| Version | `3.5.35` |
| License | MIT (© 2013–present, Yuxi "Evan" You) |
| Language | TypeScript (compiled to ES2016 for browser builds, ES2019 for Node/SSR) |
| Package manager | pnpm `11.3.0` (enforced via `only-allow`) |
| Module system | ESM-first (`"type": "module"`) |
| Build tool | Rollup `4.x` with `rollup-plugin-esbuild`; SWC for minification |
| Test runner | Vitest `4.x` (jsdom for DOM tests, Puppeteer for e2e) |
| Node requirement | `>= 20.0.0` |
| Total source | ~1.69M chars across 677 files, 42 high-priority source folders |

The architectural throughline: **the compiler turns templates into render functions; the reactivity system tracks state; the runtime renders and patches the DOM (or any custom target) in response to reactive change.** Each concern is a separate package so it can be tree-shaken, reused (e.g. `@vue/reactivity` standalone), or retargeted (custom renderers, SSR, the test renderer).

---

## 2. Repository Architecture

### 2.1 Monorepo layout

```
core/
├── packages/                    Published packages
│   ├── reactivity/              @vue/reactivity   — standalone reactivity system
│   ├── shared/                  @vue/shared       — internal utilities (private)
│   ├── runtime-core/            @vue/runtime-core — renderer, component model (platform-agnostic)
│   ├── runtime-dom/             @vue/runtime-dom  — DOM-specific renderer + browser APIs
│   ├── runtime-test/            @vue/runtime-test — test renderer (private)
│   ├── compiler-core/           @vue/compiler-core— platform-agnostic template compiler
│   ├── compiler-dom/            @vue/compiler-dom — DOM-specific compiler transforms
│   ├── compiler-sfc/            @vue/compiler-sfc — single-file-component compiler
│   ├── compiler-ssr/            @vue/compiler-ssr — SSR codegen (private)
│   ├── server-renderer/         @vue/server-renderer — SSR runtime
│   ├── vue/                     vue              — the umbrella package (full + runtime builds)
│   └── vue-compat/              @vue/compat      — Vue 2 migration build
├── packages-private/            Non-published tooling & tests
│   ├── sfc-playground/          The online SFC playground (Vite app)
│   ├── template-explorer/       Compiler output explorer (Monaco)
│   ├── dts-test/                Type-level tests (tsc-checked)
│   ├── dts-built-test/          Tests against rolled-up .d.ts
│   └── vite-debug/              Vite integration debug harness
├── scripts/                     Build/dev/release Node scripts
├── changelogs/                  Generated changelog history
├── rollup.config.js             Main build configuration
├── rollup.dts.config.js         .d.ts rollup configuration
├── tsconfig.json / .build.json  TypeScript configuration
├── vitest.config.ts             Test configuration (4 projects)
└── eslint.config.js             Lint rules (with codebase-specific bans)
```

### 2.2 Package dependency graph

The dependency direction is strictly one-way (lower layers never import higher layers):

```
                         shared  (leaf — depended on by everything)
                           ▲
        ┌──────────────────┼──────────────────────────┐
   reactivity         compiler-core                     │
        ▲                  ▲                            │
   runtime-core       compiler-dom                      │
        ▲                  ▲          ▲                 │
   runtime-dom        compiler-ssr   compiler-sfc ──────┤
        ▲                  ▲          ▲                 │
        └──────► vue ◄─────┴──────────┘                 │
                  ▲                                      │
            server-renderer ────────────────────────────┘
```

| Package | Depends on (workspace) | Role |
|---|---|---|
| `@vue/shared` | — | Pure utility functions, shared constants, type helpers. |
| `@vue/reactivity` | `shared` | The reactivity engine (`ref`, `reactive`, `effect`, `computed`, `watch`). |
| `@vue/runtime-core` | `reactivity`, `shared` | Virtual DOM, component lifecycle, the platform-agnostic renderer (`createRenderer`). |
| `@vue/runtime-dom` | `runtime-core`, `reactivity`, `shared`, `csstype` | DOM node ops, attribute/prop patching, `createApp`, `Transition`, custom elements. |
| `@vue/compiler-core` | `shared`, `@babel/parser`, `estree-walker`, `source-map-js`, `entities` | Parse → transform → codegen for templates. |
| `@vue/compiler-dom` | `compiler-core`, `shared` | DOM-specific parser options and directive transforms. |
| `@vue/compiler-ssr` | `compiler-dom`, `shared` | Generates SSR render functions. |
| `@vue/compiler-sfc` | `compiler-core`, `compiler-dom`, `compiler-ssr`, `shared`, `@babel/parser`, `magic-string`, `postcss`, `estree-walker`, `source-map-js` | Compiles `.vue` files (template + script + style). |
| `@vue/server-renderer` | `compiler-ssr`, `shared`, `vue` | Renders apps to strings/streams. |
| `vue` | `compiler-dom`, `compiler-sfc`, `runtime-dom`, `server-renderer`, `shared` | Umbrella package; full + runtime-only builds. |
| `@vue/vue-compat` | `@babel/parser`, `entities`, `estree-walker`, `source-map-js`, `vue` | Vue 2 compatibility build. |

> [!NOTE]
> `@vue/shared` is private to the framework (it has no `dependencies` of its own and is never meant to be installed directly by users). It contains the small utilities (`extend`, `isObject`, `hasChanged`, `NOOP`, `camelize`, `normalizeClass`, patch/shape flags, etc.) reused across every layer to keep bundle size down — note the ESLint rule that bans object spread in favor of `extend` from this package.

### 2.3 The `vue` umbrella package and its entries

The `vue` package re-exports `@vue/runtime-dom` and adds the in-browser compiler. Its `exports` map publishes several subpaths:

| Subpath | Resolves to | Purpose |
|---|---|---|
| `vue` | `dist/vue.runtime.esm-bundler.js` (import) / `index.js` (require) | Main entry (runtime-only by default). |
| `vue/server-renderer` | `@vue/server-renderer` | SSR functions. |
| `vue/compiler-sfc` | `@vue/compiler-sfc` (browser variant available) | SFC compiler, for tooling and the playground. |
| `vue/jsx-runtime` / `vue/jsx-dev-runtime` | `jsx-runtime/index.js` | Automatic JSX runtime (`h`-based). |
| `vue/jsx` | `jsx.d.ts` | JSX type definitions. |

The umbrella's `packages/vue/src/index.ts` registers the runtime compiler via `registerRuntimeCompiler(compileToFunction)` — this is the mechanism that lets the **full build** compile string templates on the fly, while the **runtime-only build** omits it entirely.

---

## 3. Build System

### 3.1 Build formats

Each package declares its target formats in `package.json`'s `buildOptions.formats`. The `vue` package builds all seven:

| Format | Output suffix | Module type | Notes |
|---|---|---|---|
| `esm-bundler` | `.esm-bundler.js` | ES | For bundlers; leaves `__DEV__` etc. as flags for the bundler to define. |
| `esm-bundler-runtime` | `.runtime.esm-bundler.js` | ES | Runtime-only bundler build (the default `vue` entry). |
| `esm-browser` | `.esm-browser.js` | ES | Self-contained for native `<script type=module>`. |
| `esm-browser-runtime` | `.runtime.esm-browser.js` | ES | Runtime-only native ESM. |
| `cjs` | `.cjs.js` / `.cjs.prod.js` | CommonJS | Node (SSR, tests). Targets ES2019. |
| `global` | `.global.js` / `.global.prod.js` | IIFE | Exposes `window.Vue`. |
| `global-runtime` | `.runtime.global.js` | IIFE | Runtime-only global. |

### 3.2 `rollup.config.js` internals

`rollup.config.js` is the single source of build truth. Key behaviors:

- **Target selection.** It requires the `TARGET` environment variable (the package name) and throws `TARGET package must be specified via --environment flag.` if missing. `scripts/build.js` sets it per-package.
- **Compile-time defines (`resolveDefine`).** Every build inlines a map of constants via esbuild's `define` (and the `@rollup/plugin-replace` plugin where esbuild's literal-only rules fall short). These constants drive dead-code elimination.
- **Enum inlining.** `scripts/inline-enums.js` rewrites `const enum`-style values to literals at build time (the project bans `const enum` in source — see [Coding Standards](#7-coding-standards--conventions) — and inlines plain enums instead).
- **Externalization (`resolveExternal`).** For Node/bundler builds, all direct deps and peer deps are externalized; for browser/global builds, deps are inlined (tree-shaken deps like `source-map-js`, `@babel/parser`, `estree-walker`, `entities/decode` are only listed to suppress warnings).
- **Minification.** Production browser/global builds run through an SWC-based `renderChunk` minify pass (`compress.ecma: 2016`, `mangle: true`, Safari 10 workaround), re-prepending the license banner.
- **Tree-shaking.** `treeshake.moduleSideEffects: false` lets bundlers drop unused exports; circular-dependency warnings are suppressed (they're expected and benign in the runtime).

### 3.3 Compile-time feature flags

These constants are replaced at build time. They are the closest thing Vue has to a "configuration reference" — they shape what code ends up in each bundle.

| Constant | Meaning |
|---|---|
| `__DEV__` | Development build (enables warnings, dev-only checks). In bundler ESM builds it becomes `!!(process.env.NODE_ENV !== 'production')`. |
| `__TEST__` | True only during Vue's own tests. |
| `__BROWSER__` | Build targets the browser. |
| `__GLOBAL__` | IIFE/global build. |
| `__ESM_BUNDLER__` / `__ESM_BROWSER__` | ESM bundler / browser build. |
| `__CJS__` | CommonJS build (Node). |
| `__SSR__` | Build includes SSR branches (all non-global builds). |
| `__COMPAT__` | Vue 2 compat build. |
| `__VERSION__` / `__COMMIT__` | Inlined version and commit. |
| `__FEATURE_SUSPENSE__` | Always `true` — `<Suspense>` support. |
| `__FEATURE_OPTIONS_API__` | `__VUE_OPTIONS_API__` in bundler builds (user-tunable); `true` otherwise. |
| `__FEATURE_PROD_DEVTOOLS__` | `__VUE_PROD_DEVTOOLS__` in bundler builds; `false` otherwise. |
| `__FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__` | `__VUE_PROD_HYDRATION_MISMATCH_DETAILS__` in bundler builds; `false` otherwise. |

> [!IMPORTANT]
> The three `__VUE_*` flags are the only ones intended for *downstream* consumers to define in their bundler. The rest are resolved entirely within Vue's own build. If you ship a library that bundles Vue, define `__VUE_OPTIONS_API__`, `__VUE_PROD_DEVTOOLS__`, and `__VUE_PROD_HYDRATION_MISMATCH_DETAILS__` to avoid "feature flag not defined" warnings.

### 3.4 Type declaration build

`build-dts` runs `tsc -p tsconfig.build.json --noCheck` to emit raw `.d.ts` into `temp/`, then `rollup.dts.config.js` rolls each package's declarations into a single `dist/{pkg}.d.ts` using `rollup-plugin-dts`. A custom `patchTypes` plugin (AST-driven, via `@babel/parser` + `magic-string`) converts re-exported types to inline exports (so VitePress/`defineComponent` inference works) and appends per-package type augmentations (JSX, macros). For the `vue` package, a `copyMts` plugin duplicates `vue.d.ts` to `vue.d.mts` so Node ESM and CJS both get correct types.

---

## 4. Development & Operations

### 4.1 npm scripts (the operational CLI surface)

The root `package.json` scripts are how everything is built, tested, and released:

| Script | Command | Purpose |
|---|---|---|
| `dev` | `node scripts/dev.js` | Watch-build a single package for development. |
| `build` | `node scripts/build.js` | Production build of all (or selected) packages. |
| `build-dts` | `tsc … && rollup -c rollup.dts.config.js` | Build rolled-up type declarations. |
| `clean` | `rimraf …` | Remove `dist/`, `temp/`, eslint cache. |
| `check` | `tsc --incremental --noEmit` | Full type check. |
| `lint` | `eslint --cache .` | Lint the codebase. |
| `format` / `format-check` | `prettier --write/--check` | Code formatting. |
| `test` | `vitest` | Run all tests (watch by default). |
| `test-unit` | `vitest --project unit*` | Unit tests only. |
| `test-e2e` | build global + `vitest --project e2e` | Puppeteer end-to-end tests. |
| `test-dts` | `run-s build-dts test-dts-only` | Type-level tests against built `.d.ts`. |
| `test-coverage` | `vitest run --project unit* --coverage` | Coverage report (v8 provider). |
| `size` | `run-s size-* && node scripts/usage-size.js` | Measure bundle sizes. |
| `bench` / `bench-compare` | `vitest bench …` | Reactivity/runtime benchmarks. |
| `release` | `node scripts/release.js` | Cut a release. |
| `changelog` | `conventional-changelog -p angular …` | Generate the changelog. |
| `dev-sfc` | `run-s dev-sfc-prepare dev-sfc-run` | Run the SFC playground against local source. |

> [!TIP]
> `pnpm dev <package>` (e.g. `pnpm dev reactivity`) rebuilds one package on change — the fastest loop when working on a single layer. `pnpm dev-sfc` spins up the playground wired to your local build, which is the best way to exercise the full compile→render path interactively.

### 4.2 Git hooks and commit conventions

`simple-git-hooks` (installed via `postinstall`) wires:

- **pre-commit:** `pnpm lint-staged && pnpm check` — lints staged files (ESLint + Prettier) and runs a full type check.
- **commit-msg:** `node scripts/verify-commit.js` — enforces Conventional Commits.

`lint-staged` runs Prettier on `*.{js,json}` and ESLint `--fix` + Prettier on `*.ts(x)`.

> [!CAUTION]
> The pre-commit hook runs a full `tsc --noEmit`, which can take significant time on a cold cache. Do not bypass it with `--no-verify` unless you have separately verified types — a type regression that lands on `main` breaks every downstream consumer's build.

### 4.3 Testing architecture

`vitest.config.ts` defines four test projects:

| Project | Environment | Scope |
|---|---|---|
| `unit` | node | Most packages; excludes DOM-coupled packages and e2e. |
| `unit-gc` | node (`--expose-gc`, forks pool) | `server-renderer`'s `ssrWatch` GC test. |
| `unit-jsdom` | jsdom | `vue`, `vue-compat`, `runtime-dom` tests that need a DOM. |
| `e2e` | jsdom | `packages/vue/__tests__/e2e/*` (Puppeteer-driven). |

The config also defines the same compile-time flags as the build (with `__DEV__: true`, `__TEST__: true`, `__FEATURE_*` enabled) and aliases workspace packages via `scripts/aliases.js` so tests run against source, not built output. Coverage uses the v8 provider over `packages/*/src/**`, excluding entries that are not meaningfully unit-testable (e.g. `profiling.ts`, `featureFlags.ts`, `hydrationStrategies.ts`, `Transition*`).

> [!NOTE]
> Type-level correctness is tested separately from runtime behavior: `packages-private/dts-test` contains `.test-d.ts(x)` files checked by `tsc`, and `dts-built-test` verifies the *rolled-up* declarations. A change that compiles but breaks public types is caught here, not by Vitest.

---

## 5. Reactivity Internals

The reactivity system was substantially rewritten for Vue 3.5 to use a **doubly-linked-list dependency graph with version counters**, replacing the older Set-based dependency collection. This is the most performance-critical subsystem in the framework.

### 5.1 Core data structures (`packages/reactivity/src/dep.ts`, `effect.ts`)

| Type | Role |
|---|---|
| `Dep` | A dependency: one reactive property (or a computed/ref). Holds a `version` counter and a doubly-linked list of subscriber `Link`s (`subs`). |
| `Subscriber` | Anything that consumes reactive state: a `ReactiveEffect` or a `ComputedRefImpl`. Holds a doubly-linked list of its dependencies (`deps`/`depsTail`) and a bitmask of `flags`. |
| `Link` | A node connecting one `Dep` to one `Subscriber`. Because the relationship is many-to-many, each link participates in *two* doubly-linked lists: the sub's dep-list (`nextDep`/`prevDep`) and the dep's sub-list (`nextSub`/`prevSub`). Each link carries a `version`. |
| `targetMap` | A `WeakMap<object, Map<key, Dep>>` storing the `{ target → key → Dep }` graph for `reactive` objects. |

```
   reactive object property              effect / computed
        (a Dep)                           (a Subscriber)
          │                                     │
          ├── subs ──► Link ◄── deps ───────────┤
          │            │  ▲                      │
          │         nextSub nextDep              │
          ▼            ▼  │                      ▼
        (more subs)   Link (more deps)
```

### 5.2 Tracking and triggering

- **`track(target, type, key)`** (called from proxy getters) finds (or lazily creates) the `Dep` for `target[key]` in `targetMap`, then calls `dep.track()`. If an effect is active (`activeSub`) and `shouldTrack` is on, it creates or reuses a `Link` between the dep and the active subscriber, appending it to the sub's dep-list tail.
- **`trigger(target, type, key, …)`** finds affected deps and calls `dep.trigger()`, which bumps `dep.version` and the module-global `globalVersion`, then notifies subscribers. Array `length` changes, `ADD`/`DELETE`/`CLEAR` operations, and Map/Set iteration keys (`ITERATE_KEY`, `MAP_KEY_ITERATE_KEY`, `ARRAY_ITERATE_KEY`) are handled with special cases so iteration-dependent effects re-run correctly.

### 5.3 The `globalVersion` fast path

Every reactive mutation increments `globalVersion`. A `ComputedRefImpl` records the `globalVersion` at its last evaluation. When a computed is read, if `globalVersion` hasn't changed since, it can skip dependency-checking entirely — no reactive state changed anywhere, so the cache is definitely valid. This is a cheap global short-circuit before the finer-grained per-dep version check.

### 5.4 Batching (`effect.ts`)

Notifications are **batched**. `startBatch()`/`endBatch()` bracket a trigger; subscribers are collected into `batchedSub`/`batchedComputed` linked lists (marked with the `NOTIFIED` flag) and flushed at the end of the batch — effects run in original order, computeds are processed separately. Mutating methods that change array length (`push`, `pop`, `splice`, etc.) wrap their work in `pauseTracking()` + `startBatch()` to avoid the infamous length-tracking infinite loop (issue #2137).

### 5.5 Effect flags

`ReactiveEffect` and `ComputedRefImpl` carry a bitmask (`EffectFlags`) instead of multiple booleans, for compactness and speed:

| Flag | Meaning |
|---|---|
| `ACTIVE` | The effect has not been stopped. |
| `RUNNING` | Currently executing (used to detect/guard recursion). |
| `TRACKING` | Should record dependencies while running. |
| `NOTIFIED` | Already queued in the current batch. |
| `DIRTY` | Needs re-evaluation (a dep changed). |
| `ALLOW_RECURSE` | May re-trigger itself. |
| `PAUSED` | Paused via `.pause()` — triggers are deferred. |
| `EVALUATED` | (computed) Has been evaluated at least once. |

### 5.6 Proxy handlers

- **`baseHandlers.ts`** — `BaseReactiveHandler` (get), `MutableReactiveHandler` (get/set/deleteProperty/has/ownKeys), and `ReadonlyReactiveHandler` (blocks writes, warns in dev). The getter handles ref-unwrapping, the `__v_*` reactive flags (`IS_REACTIVE`, `IS_READONLY`, `IS_SHALLOW`, `RAW`, `SKIP`), array instrumentation, and lazy nested proxying. Four singleton handlers are exported: `mutableHandlers`, `readonlyHandlers`, `shallowReactiveHandlers`, `shallowReadonlyHandlers`.
- **`collectionHandlers.ts`** — Special handling for `Map`/`Set`/`WeakMap`/`WeakSet`, whose methods (`get`/`set`/`add`/`delete`/`has`/`forEach`/iterators) must be instrumented rather than proxied via property access. Identity-key consistency is checked in dev (the "raw and reactive versions of the same object" warning).
- **`arrayInstrumentations.ts`** — Reactive-aware versions of array methods. Iteration methods (`map`, `filter`, `forEach`, `find`, `includes`, `indexOf`, etc.) take an `ARRAY_ITERATE` dependency and wrap returned items in reactive proxies as needed. Identity-sensitive searches (`includes`/`indexOf`/`lastIndexOf`) retry with raw values so you can search by either the reactive or raw form.

### 5.7 Public surface vs. internal

`packages/reactivity/src/index.ts` exports the public API (`ref`, `reactive`, `computed`, `watch`, `effect`, `effectScope`, the type set, and the `TrackOpTypes`/`TriggerOpTypes`/`ReactiveFlags` enums). The `Dep`, `Link`, `Subscriber`, `targetMap`, `globalVersion`, and batching internals are **not** part of the public contract — `runtime-core` augments `RefUnwrapBailTypes` via declaration merging to teach ref-unwrapping about VNodes and component instances without creating a runtime dependency cycle.

---

## 6. Compiler & Runtime Pipeline

### 6.1 Compiler stages

The template compiler is a classic three-stage pipeline, split across `compiler-core` (platform-agnostic) and `compiler-dom` (browser specifics):

```
template string
   │  baseParse()            ── parser.ts → AST (RootNode)
   ▼
   AST
   │  transform()            ── transform.ts: node + directive transforms
   │    nodeTransforms:      transformElement, transformExpression, vIf, vFor,
   │                         vSlot, vOnce, vMemo, cacheStatic (static hoisting)…
   │    directiveTransforms:  vBind, vOn, vModel, vShow, vHtml, vText…
   ▼
   transformed AST (with codegenNode)
   │  generate()             ── codegen.ts → render function source + sourcemap
   ▼
   { code, ast, map }
```

- **`compiler-core`** exposes `baseCompile`, `baseParse`, `transform`, `generate`, plus every individual transform and the `ErrorCodes`/`createCompilerError` machinery. It is target-agnostic.
- **`compiler-dom`** supplies `parserOptions` (HTML namespaces, native tags), DOM directive transforms (`v-html`→`transformVHtml`, `v-text`, `v-model` override, `v-on` override, `v-show`, `<Transition>`), and `stringifyStatic` (turns large static subtrees into a single `innerHTML` string for performance). Its `compile()` composes these into `baseCompile`.
- **`compiler-ssr`** reuses the DOM parser/transforms but swaps in SSR-specific transforms (`ssrTransformElement`, `ssrTransformComponent`, `ssrVIf`, `ssrVFor`, `ssrVModel`, `ssrVShow`, CSS-var injection) and emits SSR render functions via `ssrCodegenTransform`.

### 6.2 SFC compilation (`compiler-sfc`)

`@vue/compiler-sfc` is the bridge that build tools (`@vitejs/plugin-vue`, `vue-loader`) call. Its public API:

| Function | Purpose |
|---|---|
| `parse(source)` | Split a `.vue` file into `<template>`, `<script>`, `<script setup>`, and `<style>` descriptor blocks (cached via `parseCache`). |
| `compileTemplate(options)` | Compile the template block to a render function. |
| `compileScript(descriptor, options)` | Process `<script setup>`, resolve the macros (`defineProps`/`defineEmits`/`defineModel`/…), and merge with `<script>`. |
| `compileStyle` / `compileStyleAsync` | Scoped CSS, CSS Modules, and `v-bind()` in CSS via PostCSS. |
| `rewriteDefault` / `rewriteDefaultAST` | Rewrite a module's default export for composition. |
| `resolveTypeElements` / `inferRuntimeType` | Type-only prop/emit resolution (turns TS types into runtime declarations). |

It bundles a forked `@vue/consolidate` for alternative template engines and exposes `babelParse`, `MagicString`, and `walk` for tooling.

> [!NOTE]
> `shouldTransformRef` and the old reactivity-transform are gone — `compiler-sfc` keeps `shouldTransformRef = () => false` only to avoid breaking `vite-plugin-vue < 5.0` that passed `reactivityTransform: true`. Do not build new features on reactivity transform.

### 6.3 Runtime rendering (`runtime-core` → `runtime-dom`)

`runtime-core` is platform-agnostic. `createRenderer(options)` takes a set of **node operations** (create/insert/remove/patchProp/…) and returns a `{ render, createApp }` pair. This is how Vue supports multiple targets:

| Renderer | Node ops source | Target |
|---|---|---|
| `runtime-dom` | `nodeOps` + `patchProp` (`packages/runtime-dom/src`) | Real browser DOM. |
| `runtime-test` | `nodeOps` + `patchProp` (`packages/runtime-test/src`) | An in-memory tree for assertions (`serializeInner`, `triggerEvent`). |
| Your custom renderer | your own ops | Canvas, native, terminal, etc. |

`runtime-dom` lazily instantiates the renderer (`ensureRenderer`) so apps that only use the reactivity APIs don't pull in renderer code. `createApp` wraps the core app to add DOM container normalization, in-DOM template handling (full build), and dev-only checks (`isNativeTag`, deprecated-`isCustomElement`/`compilerOptions` guards). `createSSRApp` uses the **hydration** renderer (`createHydrationRenderer`) to adopt server markup instead of creating new nodes.

### 6.4 Hydration strategies (lazy hydration)

`runtime-core` exports `hydrateOnIdle`, `hydrateOnVisible`, `hydrateOnMediaQuery`, and `hydrateOnInteraction` — strategy factories for deferring hydration of async components until the browser is idle, the element is visible, a media query matches, or the user interacts. These power "islands"-style performance patterns.

---

## 7. Coding Standards & Conventions

`eslint.config.js` enforces several codebase-specific rules that contributors must respect:

| Rule | Rationale |
|---|---|
| **No `const enum`** | The project inlines plain enums at build time; `const enum` breaks isolated modules. Use a regular `enum`. |
| **No object rest in destructuring** (`{ ...rest }` patterns) | Output target is ES2016; rest/spread produces verbose helpers. |
| **No object spread in expressions** (`{ ...obj }`) | esbuild transpiles it to verbose inline helpers — use `extend()` from `@vue/shared`. |
| **No `async`/`await` syntax** | ES2016 target; avoid the generated state machine. Use promises/`.then` or the compiler's async helpers. |
| **No optional chaining (`?.`)** | ES2016 target; it transpiles to verbose helpers. |
| **No raw Node.js modules** (except `node:`-prefixed, and inside `compiler-sfc`) | Most of the codebase must be environment-agnostic. |
| **No DOM globals** (`window`, `document`) in env-agnostic packages | Enforced per-package: DOM packages may use DOM globals, Node packages may use Node globals, `shared` may use neither restriction. |
| **`import type` required** for type-only imports | Keeps the runtime graph clean and tree-shakeable. |
| **Prefer `@ts-expect-error` over `@ts-ignore`** | Surfaces stale suppressions. |

> [!IMPORTANT]
> These bans exist because Vue's source is shipped to users essentially as-authored (after esbuild transpilation to ES2016). Convenience syntax that looks free in app code (spread, `async/await`, `?.`) expands into helper functions that bloat the framework's own bundle. When in doubt, mirror the surrounding code and reach for `@vue/shared` helpers.

---

## 8. Security Analysis

Vue is a client/SSR library, so its security surface is about safe rendering, not network/auth.

| Area | Behavior | Guidance |
|---|---|---|
| **HTML injection** | `v-html` and the `innerHTML`-based `stringifyStatic` optimization set raw HTML. Text interpolation (`{{ }}` / `toDisplayString`) is always escaped. | Never bind untrusted content to `v-html`. The compiler even refuses `v-html` with children and warns on `v-text` misuse. |
| **In-DOM templates** | The full build can compile a container's `innerHTML` as a template. The source explicitly marks these paths `__UNSAFE__`. | Only mount over trusted in-DOM templates; never let user-controlled markup become a template. SSR output used as a template must not contain user data. |
| **SSR escaping** | `@vue/shared`'s `escapeHtml` is used throughout the server renderer for interpolated content and attributes. | Trust the renderer's escaping for interpolations; be careful with `v-html` and any manually injected `SSRContext` data. |
| **XSS via attributes** | `runtime-dom`'s `patchProp` handles attribute vs. property assignment and supports Trusted Types (`@types/trusted-types`). | In strict-CSP/Trusted-Types environments, configure a policy; Vue is Trusted-Types-aware. |
| **Prototype pollution** | Reactive proxy handlers explicitly skip `__proto__` and non-trackable keys (`isNonTrackableKeys`). | Don't rely on inherited/proto keys being reactive. |
| **Dependency surface** | Runtime deps are minimal and well-known (`@babel/parser`, `magic-string`, `postcss`, `source-map-js`, `estree-walker`, `entities`, `csstype`); most are compiler/build-time. | Keep these patched; they affect build tooling more than runtime. |

> [!CAUTION]
> The single most common Vue security mistake is `v-html` with user content. Treat every `v-html`, `innerHTML`-equivalent render path, and selector-template mount (`#id`) as a potential XSS vector and audit accordingly.

---

## 9. Quality, Tech Debt & Improvement Areas

These are observations grounded in the current source and the community issue tracker; they are candidate areas for contributors.

- **Vapor mode is in flight.** The issue tracker shows active `[Vapor]` / `[runtime-vapor]` work (e.g. #14844, #14787, #14851) — a compilation strategy that skips the virtual DOM. It is not yet a stable public API; expect churn in compiler and runtime internals around it.
- **Reactivity edge cases.** `reactive` silently no-ops on non-extensible objects (#14893) — arguably should warn. `watch` with `immediate: true` and a static source running only once (#14898) is a recurring source of confusion; documentation/DX could be improved.
- **Type-level scaling.** Very large prop union types can trip `TS2590` ("union type too complex," #10514). Components with hundreds of literal-union prop values need workarounds.
- **Transition/animation gaps.** `<Transition>` doesn't animate `visibility` (#2531); `v-show` enter animations differ from `v-if`/`v-for` in `<TransitionGroup>` (#14894).
- **SSR hydration robustness.** Recent fixes around Teleport + Suspense unmount (#14876) and redundant mismatch logging (#14855) indicate the Teleport/Suspense/hydration intersection is a complex, regression-prone area worth additional test coverage.
- **Compiler crash hardening.** Edge-case template inputs (`<template v-for>` + non-identifier `:key` + `v-memo`, #14859) have produced compiler crashes; fuzz-style template tests would help.

> [!NOTE]
> Because Vue has no staging environment between `main` and published releases, the test matrix (unit + jsdom + e2e + dts) is the safety net. Any internals change to reactivity, the renderer, or the compiler should land with tests at the seam it touches.

---

## 10. Quick Reference

### Package → npm name

| Folder | npm package | Published? |
|---|---|---|
| `packages/vue` | `vue` | ✅ |
| `packages/reactivity` | `@vue/reactivity` | ✅ |
| `packages/runtime-core` | `@vue/runtime-core` | ✅ |
| `packages/runtime-dom` | `@vue/runtime-dom` | ✅ |
| `packages/compiler-core` | `@vue/compiler-core` | ✅ |
| `packages/compiler-dom` | `@vue/compiler-dom` | ✅ |
| `packages/compiler-sfc` | `@vue/compiler-sfc` | ✅ |
| `packages/server-renderer` | `@vue/server-renderer` | ✅ |
| `packages/vue-compat` | `@vue/compat` | ✅ |
| `packages/shared` | `@vue/shared` | ✅ (internal) |
| `packages/compiler-ssr` | `@vue/compiler-ssr` | internal |
| `packages/runtime-test` | `@vue/runtime-test` | internal |

### Common contributor commands

```bash
pnpm install                 # bootstrap (pnpm enforced)
pnpm dev reactivity          # watch-build one package
pnpm dev-sfc                 # run the SFC playground on local source
pnpm test-unit               # unit tests
pnpm test --project unit-jsdom   # DOM tests
pnpm check                   # full type check
pnpm lint                    # eslint
pnpm build vue               # production build of the vue package
pnpm build-dts               # build rolled-up type declarations
pnpm size                    # measure bundle sizes
```

### Key source files for orientation

| File | What it anchors |
|---|---|
| `packages/vue/src/index.ts` | Full build entry; registers the runtime compiler. |
| `packages/runtime-dom/src/index.ts` | `createApp`/`createSSRApp`, DOM renderer bootstrap. |
| `packages/runtime-core/src/index.ts` | The entire runtime public API surface. |
| `packages/reactivity/src/{dep,effect,computed,ref,reactive}.ts` | The reactivity engine. |
| `packages/compiler-core/src/{parser,transform,codegen}.ts` | The compiler pipeline. |
| `rollup.config.js` | Build formats, feature flags, externalization. |
| `vitest.config.ts` | Test projects and aliases. |

---

_Generated June 2026 from vuejs/core at 86ad076. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
