Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Monaco Editor — Admin & Architecture Guide

Generated June 2026 from microsoft/monaco-editor at 4cd0f4f

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.

This guide is for the engineers, architects, and release maintainers who integrate, build, ship, or extend the monaco-editor package. It explains what the repository actually is (a distribution layer over the VS Code editor), how the build pipeline turns the VS Code source tree into the monaco-editor and monaco-editor-core npm packages, the structure of every sub-package, the worker and security model, and the operational concerns of running Monaco in production.

Important

microsoft/monaco-editor is not the source of the editor engine. The engine lives in microsoft/vscode. This repository pins a specific VS Code commit (vscodeRef), builds it into the publishable monaco-editor-core package, then wraps that core with language definitions, language services, a webpack plugin, an LSP client, samples, and a website. Understanding this "published-and-consumed core" relationship is the key to everything below.


1. Executive summary

Attribute Value
Product Monaco Editor — the browser code editor that powers VS Code
This repository Distribution/packaging layer + language definitions + tooling
Primary package monaco-editor
Version (this build) 0.55.1
Engine package monaco-editor-core (built from VS Code)
Pinned VS Code commit (vscodeRef) 86f5a62f058e3905f74a9fa65d04b2f3b533408e
License MIT
Author Microsoft Corporation
Source commit documented here 4cd0f4f (2026-06-02)
Runtime Browser (client-side only; uses web workers)
Build toolchain TypeScript, ts-node, Rollup, esbuild, webpack, Playwright

What an operator needs to know in 30 seconds: Monaco is a client-side, zero-backend library. Its only "servers" are browser web workers. You consume it as an npm package or a CDN bundle. The repository's release engineering is a two-stage build: stage 1 compiles the editor out of a pinned VS Code commit into monaco-editor-core; stage 2 wraps that core into monaco-editor, runs cross-bundler smoke tests, and publishes. Versions are traceable back to exact VS Code and monaco-editor commits stamped into package.json at build time.


2. Architecture overview

2.1 Layered model

┌─────────────────────────────────────────────────────────────┐
│  Your application (web page / SPA / Electron renderer)        │
│    import * as monaco from 'monaco-editor'                     │
└───────────────────────────────┬─────────────────────────────┘
                                 │
┌───────────────────────────────▼─────────────────────────────┐
│  monaco-editor  (THIS REPO — distribution layer)              │
│   src/index.ts ─ re-exports editor.api + registers:           │
│     • features/register.all       (editor contributions)      │
│     • languages/definitions       (~90 Monarch tokenizers)    │
│     • languages/features          (CSS/HTML/JSON/TS services)  │
│     • @vscode/monaco-lsp-client   (LSP client, optional)      │
└───────────────────────────────┬─────────────────────────────┘
                                 │  import 'monaco-editor-core'
┌───────────────────────────────▼─────────────────────────────┐
│  monaco-editor-core  (published separately, built from VSCode) │
│   esm/vs/editor/editor.api  ─ the `monaco` namespace           │
│   the editor widget, view, model, tokenizer, worker host       │
└───────────────────────────────┬─────────────────────────────┘
                                 │ built from a pinned commit
┌───────────────────────────────▼─────────────────────────────┐
│  microsoft/vscode  @ vscodeRef                                 │
│   gulp editor-distro → out-monaco-editor-core                  │
└─────────────────────────────────────────────────────────────┘

2.2 The wrapper entry point

The whole packaging layer is a handful of small re-export modules. The public entry is src/index.ts:

import * as lsp from '@vscode/monaco-lsp-client';
import { css, html, json, typescript } from './languages/register.all';
import './features/register.all';

// ensure that the main monaco-editor entry-point loads all features from monaco-editor-core
import 'monaco-editor-core';

export * from './editor';
export { css, html, json, typescript, lsp };

And src/editor.ts is a single line that re-exports the engine's public API:

export * from 'monaco-editor-core/esm/vs/editor/editor.api';

Note

This is why the User Guide says "Monaco" means monaco-editor-core's API. The monaco.editor.* and monaco.languages.* surface comes from the core; this repository's job is to register the language tokenizers and the editor feature contributions into that core, plus ship the language-service workers.

2.3 Feature and language registration

src/features/register.all.ts is a flat list of side-effect imports — one per editor contribution (anchorSelect, bracketMatching, find, folding, hover, suggest, inlineCompletions, gpu, stickyScroll, and ~60 more). Each */register module pulls the corresponding contribution from monaco-editor-core. Importing monaco-editor (which imports register.all) therefore activates every editor feature.

src/languages/register.all.ts registers both:

  • ./definitions/register.all — the ~90 Monarch tokenizer definitions in src/languages/definitions/<lang>/.
  • ./features/register.all — the four rich language services (css, html, json, typescript).

This split (definitions = highlighting; features = language services) is the architectural reason the User Guide distinguishes "basic languages" from "rich language services".

2.4 The language-service adapter layer

The four rich services are powered by Microsoft's standalone language-service libraries (vscode-css-languageservice, vscode-html-languageservice, vscode-json-languageservice, and the TypeScript compiler) running in web workers. src/languages/features/common/lspLanguageFeatures.ts is the adapter layer that maps those LSP-style services onto Monaco's provider interfaces. Its classes are the bridge:

Adapter class Monaco capability it provides
DiagnosticsAdapter Live validation markers
CompletionAdapter Autocomplete suggestions
HoverAdapter Hover tooltips
DocumentHighlightAdapter Occurrence highlighting
DefinitionAdapter Go-to-definition
ReferenceAdapter Find-all-references
RenameAdapter Symbol rename
DocumentSymbolAdapter Outline / breadcrumbs
DocumentLinkAdapter Clickable links
DocumentFormattingEditProvider / DocumentRangeFormattingEditProvider Formatting
DocumentColorAdapter Color decorators/picker
FoldingRangeAdapter Folding regions
SelectionRangeAdapter Smart-select expand/shrink

Tip

If you are building your own rich language service, this adapter file is the reference implementation for wiring an LSP-style server (one that speaks the language-server feature set) into Monaco's provider API.

2.5 The worker host

src/internal/common/workers.ts and initialize.ts implement the bridge between Monaco's worker host and the browser:

  • getWorker(descriptor) consults globalThis.MonacoEnvironment for either getWorker(moduleId, label) or getWorkerUrl(moduleId, label). If neither is defined and no createWorker is supplied, it throws the familiar You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker error.
  • createWebWorker<T>(opts) wraps the resolved Worker and hands it to the core's editor.createWebWorker.
  • A Trusted Types policy (defaultWorkerFactory) is created via MonacoEnvironment.createTrustedTypesPolicy (if the host provides one) or globalThis.trustedTypes.createPolicy, so worker script URLs are minted through a CSP-compliant policy.

3. Repository structure

Path Purpose Published as
src/ The wrapper: index.ts, editor.ts, features/, languages/, internal/ part of monaco-editor
src/languages/definitions/<lang>/ Monarch tokenizers (~90 languages) + grammar tests part of monaco-editor
src/languages/features/{css,html,json,typescript}/ Rich language-service contributions + workers part of monaco-editor
src/deprecated/ Old import paths kept for back-compat part of monaco-editor
monaco-lsp-client/ @vscode/monaco-lsp-client — LSP client package separate npm package
webpack-plugin/ monaco-editor-webpack-plugin (v7.1.1) separate npm package
samples/ Integration samples for every bundler + Electron/NW.js monaco-editor-samples (not published to consumers)
website/ The monaco-editor.github.io site, playground, typedoc deployed to GitHub Pages
test/manual/ Manual interactive test harness dev only
test/smoke/ Playwright cross-bundler smoke tests dev only
scripts/ci/ Release build orchestration (TypeScript) dev only
scripts/lib/ Shared build helpers (git clone, run, versioning) dev only
build/ Editor build, postinstall, sample checks, npm helpers dev only

Note

samples/legacy/ contains AMD-based samples (browser-amd-*, electron-amd*, nwjs-amd*). Per the repo's own note these "are not supported anymore and will be removed in future releases." Steer integrators to the ESM samples.


4. Build & release pipeline

The release is a two-stage process orchestrated by TypeScript files under scripts/ci/, each runnable with a stable or nightly argument.

4.1 Stage 1 — build monaco-editor-core from VS Code

scripts/ci/build-monaco-editor-core-pkg.ts:

  1. Reads version and vscodeRef from the root package.json.
  2. For stable: uses those values verbatim. For nightly: computes a version with getNightlyVersion() (→ 0.<minor+1>.0-<prerelease>, where <prerelease> interpolates today's date) and reads VSCODE_REF from the environment.
  3. Shallow-clones microsoft/vscode at the ref and microsoft/vscode-loc (localizations) as a sibling.
  4. Stamps the resolved version and vscodeCommitId into VS Code's build/monaco/package.json.
  5. Runs the full VS Code build & test gate, then gulp editor-distro, producing out-monaco-editor-core ready to publish.

The VS Code build/test gate (buildAndTest()) runs, in order:

npm install
npm run playwright-install
npm run gulp hygiene
npm run valid-layers-check
npm run eslint
npm run monaco-compile-check
npm run --max_old_space_size=4095 compile
npm run gulp editor-distro
npm run test-browser -- --browser chromium
# typings smoke test: tsc against out-monaco-editor-core
# monaco tests: esm-check, bundle-webpack, compile, test (in vscode/test/monaco)

4.2 Stage 2 — build monaco-editor from the core

scripts/ci/build-monaco-editor-pkg.ts:

  1. npm ci in webpack-plugin/.
  2. Sets the monaco-editor version (stable: the package version; nightly: computed) and pins devDependencies['monaco-editor-core'] to the matching core version.
  3. npm install to pull the new core.
  4. CVE tracking: merges monaco-editor-core's runtime dependencies into monaco-editor's dependencies (throwing if any key would be overwritten) so the published package's dependency tree reflects what the core actually bundles.
  5. Stamps vscodeCommitId (from the core) and monacoCommitId (this repo's HEAD) into package.json for full provenance.
  6. Builds and tests:
npm run build            # build-lsp + build-monaco-editor
npm test                 # check-samples + grammar tests
npm run compile          # webpack-plugin
npm run package-for-smoketest-webpack
npm run package-for-smoketest-esbuild
npm run package-for-smoketest-vite
npm run smoketest        # Playwright across the packaged bundles
# → ./out/monaco-editor ready to publish

4.3 Environment contract

scripts/ci/env.ts requires two environment variables for nightly builds, failing fast if absent:

Variable Used for
VSCODE_REF Which VS Code commit to build the nightly core from.
PRERELEASE_VERSION The prerelease suffix template (supports ${today}).

Important

Provenance is a first-class design goal here. Every published monaco-editor records vscodeCommitId and monacoCommitId. Given any installed version you can determine the exact VS Code commit and monaco-editor commit it was built from — critical for security triage and reproducing bugs.

4.4 Local build scripts (root package.json)

Script Action
build build-lsp then build-monaco-editor.
build-monaco-editor ts-node ./build/build-monaco-editor.
build-lsp cd monaco-lsp-client && npm install && npm run build.
build-all build plus packaging all smoke-test fixtures.
watch tsc -w -p ./src.
import-typescript ts-node ./build/importTypescript (refreshes the bundled TS lib).
simpleserver ts-node ./build/simpleserver (serve locally).
test build/check-samples + test:grammars.
test:grammars node --test over src/languages/definitions/*/*.test.ts.
smoketest playwright test --config=test/smoke/playwright.config.ts.

5. The webpack plugin (monaco-editor-webpack-plugin)

A separately published package (v7.1.1) that frees integrators from hand-writing the MonacoEnvironment worker wiring.

5.1 What it does

On apply(compiler) it:

  1. Reads metadata.js from the resolved monaco-editor install to learn every available feature and language and their worker entry points.
  2. Resolves the desired subset from the user's languages/features options.
  3. Generates a MonacoEnvironment global (via an include-loader rule on editor.api|main.js) whose getWorkerUrl maps each label to the emitted worker filename — including the cross-origin Blob-proxy fallback.
  4. Registers an AddWorkerEntryPointPlugin per worker, each wrapped with webpack's LimitChunkCountPlugin({ maxChunks: 1 }) so every worker compiles to a single file.

5.2 Options

Option Type Default Purpose
languages EditorLanguage[] all Include only this subset of languages.
customLanguages IFeatureDefinition[] — Add languages not shipped with monaco-editor.
features (EditorFeature | NegatedEditorFeature)[] all Include a subset; prefix with ! to exclude (e.g. '!contextmenu').
filename string '[name].worker.js' Worker filename template (supports [contenthash]).
monacoEditorPath string auto-resolved Absolute path to the monaco-editor module.
publicPath string '' Override the public path workers load from (useful for CDNs / cross-origin).
globalAPI boolean false Expose the editor API as a global monaco object (the ESM build does not by default since 0.22.0).

Note

Feature exclusion is all-or-subset: if any entry in features starts with !, the plugin treats the list as "all features minus the negated ones"; otherwise the list is treated as an explicit allow-list. Worker sharing is built in — the typescript worker is reused for javascript, the css worker for scss/less, and the html worker for handlebars/razor.

5.3 Compatibility

Peer dependency Range
webpack ^4.5.0 || 5.x
monaco-editor >= 0.31.0

Runtime dependency: loader-utils (for worker filename interpolation).


6. The LSP client (@vscode/monaco-lsp-client)

A separate package (v0.1.0) for connecting Monaco to a real Language Server over a transport. Its public surface:

export { MonacoLspClient, WebSocketTransport, createTransportToWorker, createTransportToIFrame };
Export Purpose
MonacoLspClient Connects an LSP server to Monaco's language-feature registries.
WebSocketTransport LSP over a WebSocket (server-backed language servers).
createTransportToWorker LSP to a server running in a web worker.
createTransportToIFrame LSP to a server running in an iframe.

It is built with rolldown and depends on the @hediet/json-rpc family for the typed RPC contract. A code generator (monaco-lsp-client/generator/index.ts, LSPTypesGenerator) reads the LSP metaModel.json and emits src/types.ts — typed request/notification contracts plus a capabilities map and an api contract object. Regenerate with npm run generate (tsx generator/index.ts).

Warning

Known issue #5340: MonacoLspClient does not dispose its language-feature registrations, which can leak provider registrations across reconnects. Known issue #5342: textDocument/codeAction requests omit diagnostic fields (data, code, source) some servers need for quick-fixes. Track both if you build on this client; it is an early-version (0.1.0) package.


7. Worker & runtime model

  • Everything is client-side. There is no server component. "Workers" are browser web workers.
  • One core worker + four service workers. The core editor.worker handles text diffing, tokenization handoff, and link detection. Each rich service (ts.worker, json.worker, css.worker, html.worker) runs its language analysis off the UI thread.
  • Worker resolution is host-supplied. Monaco never hard-codes worker URLs; the host provides them through MonacoEnvironment (Section 2.5). Bundler plugins/configs generate that wiring.
  • Idle models. createWebWorker accepts keepIdleModels; by default idle models stop syncing to the worker after a while to save memory.

8. Security

Caution

Monaco renders untrusted text and, for some features (hovers, suggestion docs), renders Markdown. Treat the following as required hardening when embedding Monaco in a security-sensitive context.

8.1 Trusted Types & CSP

The worker host mints worker script URLs through a Trusted Types policy named defaultWorkerFactory. If your page enforces Trusted Types, supply MonacoEnvironment.createTrustedTypesPolicy(name, options) so Monaco routes script-URL creation through your approved policy. For Content Security Policy, allow worker-src blob: (Monaco may construct workers from Blob URLs, especially in the cross-origin case) and the worker script origins.

8.2 DOMPurify advisory (CVE-2026-0540)

Monaco renders Markdown (in hovers and suggestion documentation) using marked + dompurify, carried transitively via the bundled core. Issue #5248 tracks CVE-2026-0540, a cross-site scripting vulnerability in DOMPurify.

  • Mitigation: Upgrade to a monaco-editor release whose bundled core ships a patched DOMPurify. Because the two-stage build merges core dependencies into the published monaco-editor package.json (Section 4.2), you can audit the DOMPurify version directly from your installed package's dependency tree.
  • Defense in depth: Do not feed fully attacker-controlled HTML into hover/markdown content you register via custom providers.

8.3 Pinned security-sensitive deps

Issue #5314 asks why marked and dompurify versions are fixed — the answer is deliberate: pinning these markdown/sanitization dependencies keeps the security surface auditable and reproducible per release. Do not float them independently of the published lockstep.

8.4 Electron embedding

The ESM Electron sample uses webPreferences: { worldSafeExecuteJavaScript: true }. A legacy nodeIntegration-enabled sample exists (samples/legacy/electron-amd-nodeIntegration) with nodeIntegration: true, sandbox: false, contextIsolation: false — that configuration disables Electron's renderer sandbox and should not be used as a template for production apps. Prefer context isolation and a sandboxed renderer.


9. Operations

9.1 Deploying Monaco assets

Monaco is static assets. Production concerns are:

  • Serve the worker files at the URLs your MonacoEnvironment returns. A 404 on a worker disables that language's features.
  • Same-origin or cross-origin proxy. If workers live on a CDN, either set the webpack plugin's publicPath or use the Blob-proxy pattern (User Guide §3.6).
  • Caching. Worker and editor bundles are content-addressable when you use [contenthash] filenames; cache them aggressively and bust on version bumps.
  • Fonts/icons. Monaco ships a codicon.ttf; ensure your bundler emits it (e.g. webpack asset/resource for .ttf).

9.2 Health & smoke checks

The repository's own test/smoke/ Playwright suite packages the editor with webpack, esbuild, and Vite and verifies it boots and finds its workers. The playwright.config.ts honors CI and PORT environment variables. Adopt the same approach for your integration: a headless smoke test that mounts an editor and asserts a TypeScript completion appears proves your worker wiring end to end.

9.3 Performance tuning

  • Disable the minimap (minimap: { enabled: false }) and renderWhitespace for large documents.
  • Use the webpack plugin's languages/features allow-list or the editor.api opt-in build to cut bundle size.
  • Reuse models across editors instead of recreating them; dispose aggressively to free workers.

10. Troubleshooting (operational)

Worker 404 / features silently disabled

  • Cause: The worker URL your MonacoEnvironment returns isn't served.
  • Solution: Confirm the worker files are emitted and reachable at those paths; check the network tab for 404s on *.worker.js.

Error: monaco is not loaded yet

  • Cause: Global monaco accessed before the AMD loader finished (website/src/monaco-loader.ts raises this).
  • Solution: Access monaco only inside the loader callback / after the editor import resolves.

Error: InstantiationService has been disposed

  • Cause: An editor or service was used after disposal (issue #4612).
  • Solution: Ensure you don't call into an editor/model after dispose(); in SPAs, guard async callbacks that may fire after teardown.

Build error: Invalid argument

  • Cause: A CI build script was invoked without stable or nightly (build-monaco-editor-core-pkg.ts / build-monaco-editor-pkg.ts throw this).
  • Solution: Pass the channel argument explicitly.

Build error: Missing PRERELEASE_VERSION / Missing VSCODE_REF in process.env

  • Cause: A nightly build ran without its environment contract (scripts/ci/env.ts).
  • Solution: Set both env vars before a nightly build.

Auto-completion disabled for languages with id ≥ 256

  • Cause: A LanguageID/TokenType bit-overlap bug (issue #5344, closed).
  • Solution: Update to a release that includes the fix if you register very large numbers of custom languages.

11. Testing strategy

Layer Tooling Location
Grammar/tokenizer tests node --test (built-in test runner) src/languages/definitions/*/*.test.ts
Sample integrity build/check-samples run via npm test
Cross-bundler smoke Playwright test/smoke/ (webpack/esbuild/vite/parcel/amd)
Manual interactive hand-run harness test/manual/
Core editor tests VS Code's own suite (stage 1) vscode/test/monaco

The smoke tests are the integration safety net: they package the actual published shape of the editor with each bundler and run it in a real browser. The grammar tests validate every Monarch tokenizer against fixtures so language highlighting changes are caught.


12. Module reference

Module Role
src/index.ts Public entry; registers features + languages + LSP, re-exports the core API.
src/editor.ts One-line re-export of monaco-editor-core editor API.
src/features/register.all.ts Side-effect imports activating every editor contribution.
src/languages/definitions/ Monarch tokenizers for ~90 languages (+ grammar tests).
src/languages/features/common/lspLanguageFeatures.ts Adapter layer mapping LSP-style services to Monaco providers.
src/languages/features/{css,html,json,typescript}/ Per-language service contributions + workers.
src/internal/common/workers.ts Worker resolution + Trusted Types policy + createWebWorker.
src/internal/common/initialize.ts Worker bootstrap (self.onmessage → core worker start).
webpack-plugin/src/index.ts MonacoEditorWebpackPlugin — worker wiring + bundle slimming.
monaco-lsp-client/src/ LSP client (MonacoLspClient, transports).
monaco-lsp-client/generator/ LSP type/contract generator from metaModel.json.
scripts/ci/* Two-stage release build orchestration.
scripts/lib/index.ts Build helpers: run, gitShallowClone, getNightlyVersion, version stamping.

13. Potential improvements & known debt

  • LSP client maturity. @vscode/monaco-lsp-client is v0.1.0 with open disposal (#5340) and code-action field (#5342) bugs. Treat as experimental; pin and test before depending on it.
  • Two ESM variants requested. Issue #5067 ("Ship two esm variants") and #886 ("ESM and CSS loading") point at ongoing friction in the ESM/CSS delivery story; expect packaging changes across minor versions.
  • NLS double-extension packaging bug. Issue #5345 — localized nls.messages.<lang>.js.js files in 0.55.x. If you ship localizations, verify emitted filenames.
  • Accessibility backlog. Several open a11y issues (focus management after closing search #5328, tab order in find/replace #5329, suggestion-list contrast #5307, system-theme adoption #5312). Audit against WCAG if accessibility is a requirement, and consider the high-contrast themes.
  • Legacy AMD samples. samples/legacy/ is explicitly slated for removal; do not build new integrations on the AMD path.

14. Quick reference

Provenance fields in package.json

Field Meaning
version Published monaco-editor version (0.55.1).
vscodeRef VS Code commit the core is built from.
vscodeCommitId Resolved VS Code commit (stamped at build).
monacoCommitId This repo's commit (stamped at build).

Entry points

Entry Use
./esm/vs/editor/editor.main.js Full editor (ESM).
./min/vs/editor/editor.main.js Full editor (AMD/min, main).
./esm/vs/editor/editor.api Editor API only.

CI build invocations

# Stage 1: build monaco-editor-core from VS Code
ts-node scripts/ci/build-monaco-editor-core-pkg.ts stable   # or nightly

# Stage 2: build monaco-editor from the core
ts-node scripts/ci/build-monaco-editor-pkg.ts stable        # or nightly

Key facts

  • License: MIT. Author: Microsoft Corporation.
  • No backend; client-side only; web-worker based.
  • monaco-editor version 0.55.1; VS Code ref 86f5a62….
  • Separate published packages: monaco-editor, monaco-editor-core, monaco-editor-webpack-plugin (7.1.1), @vscode/monaco-lsp-client (0.1.0).

Official resources

  • Repository & issues: https://github.com/microsoft/monaco-editor
  • Website / playground / typedoc: https://microsoft.github.io/monaco-editor/
  • Engine source (VS Code): https://github.com/microsoft/vscode