Monaco Editor Integration#
Dify uses Monaco Editor β the same editor that powers VS Code β for code editing in workflow nodes (the Code node, prompt editors, etc.). The integration is built on @monaco-editor/react v4.7.0 , pinned in the workspace catalog.
The primary entry point is CodeEditor at web/app/components/workflow/nodes/_base/components/editor/code-editor/index.tsx. Assets (workers, language bundles, loader) are served locally from web/public/vs/ rather than from a CDN, avoiding network dependency issues at runtime.
Asset Loading & Loader Configuration#
Monaco's AMD loader is configured at module top-level in the CodeEditor file:
// load file from local instead of cdn https://github.com/suren-atoyan/monaco-react/issues/482
if (typeof window !== 'undefined')
loader.config({ paths: { vs: `${window.location.origin}${basePath}/vs` } })
Two details are load-bearing:
- SSR guard (
typeof window !== 'undefined'): prevents the loader call from running during server-side rendering, which would throw becausewindowdoesn't exist. This was the root cause of the "dozens of errors" fixed in PR #28500. window.location.originprefix: ensures thevspath resolves correctly regardless of the application'sbasePath(i.e., when Dify is deployed at a subpath). Before this fix, the path was built as${basePath}/vs, which broke asset loading in non-root deployments .
The web/public/vs/ directory contains the full Monaco distribution: loader.js, web workers (workerMain.js), basic-language bundles (Python, JavaScript, JSON, etc.), and NLS i18n message files .
CodeEditor Component#
CodeEditor wraps @monaco-editor/react's Editor component with Dify-specific logic:
- Language mapping β translates Dify's
CodeLanguageenum to Monaco language IDs :python3 β 'python',javascript β 'javascript',json β 'json'. - Theme switching β calls
monaco.editor.setTheme()insideonMountto sync the editor with the app's light/dark theme, working around a timing issue where the default theme sometimes doesn't apply . - Auto-height β resizes the editor to fit content by reading
editor.getContentHeight()after each change. - Two layout modes:
noWrapper(bare editor, minimal height) and a fullBase-wrapped variant with title bar, code generator, and file list .
Key editor options set : minimap disabled, word wrap enabled, quick suggestions off, ambiguous character Unicode highlight suppressed, sticky scroll disabled.
Migration Attempts & Architecture Decision#
In early March 2026, the team attempted to modernize the Monaco integration away from the AMD-based @monaco-editor/react approach:
- PR #32966 β migrated to
modern-monaco@0.4.0(ESM-based, no AMD loader). Removed allweb/public/vs/assets and replaced the component wrapper. - PR #33540 β layered a "hoisting" strategy on top: a build-time script (
hoist-modern-monaco.ts) pre-processedmodern-monacomodules intoweb/public/hoisted-modern-monaco/, and a runtime ES import map resolved module specifiers to those local paths. This also handled proxy deployments via request headers.
Both were reverted the same day via PR #33566, restoring @monaco-editor/react@4.7.0 and the web/public/vs/ asset tree. The same-day revert strongly suggests unforeseen compatibility or stability issues with the modern-monaco approach. The PR body does not document specifics.
Current canonical approach: AMD loader via @monaco-editor/react, local vs/ assets, explicit loader path configuration.
Key Files & References#
| Resource | Path / Link |
|---|---|
| Main component | web/app/components/workflow/nodes/_base/components/editor/code-editor/index.tsx |
| Static Monaco assets | web/public/vs/ (loader, workers, language bundles, NLS files) |
| Dependency version | @monaco-editor/react@4.7.0 in pnpm-workspace.yaml catalog |
| Loader path fix (PR #28500) | SSR guard + correct origin-prefixed asset path |
| Modern-monaco migration attempt | PR #32966, PR #33540 |
| Revert to @monaco-editor/react | PR #33566 |
| Monaco editor options reference | https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOptions.html |