Repository navigation
Building
This page describes the public build in etc/build: what each Ant target reads and writes, the Closure Compiler settings, the bundles it produces, how to add a source file, and which parts of the shipped files the public build cannot regenerate. It is for developers who change the source and want the change in production mode, in a .war, or in a fork.
The minified bundles in src/main/webapp/js are committed, so you can run the editor straight from a clone (see Getting started). Development mode (?dev=1) loads the sources directly and never needs a build.
Build when you want to:
- see your source changes in production mode (the default URL without
?dev=1), - produce
build/draw.warfor a servlet container, - ship a fork that runs from minified bundles, for example on GitHub Pages.
| Tool | Version | Notes |
|---|---|---|
| JDK | 8, 11 or 17 | The release workflow .github/workflows/war.yml builds with Zulu JDK 8 and the docker-drawio image with JDK 11; JDK 17 works as well |
| Apache Ant | 1.10 |
ant must be on the PATH
|
| Google Closure Compiler | v20220502 | Committed as etc/build/compiler.jar, nothing to download |
No Node.js, npm or network access is needed.
All targets run from etc/build:
cd etc/build
ant # default target "all": merge, app, atlas, integrate
ant app # merge + app: the editor, viewer and extension bundles
ant war # app + javac, then packages build/draw.war
ant clean # removes compiled classes, build/ and intermediate filesA full ant run takes well under a minute. The outputs overwrite the committed files in src/main/webapp/js, so git status shows them as modified afterwards. Some differ from the committed copies even without source changes, notably viewer.min.js and viewer-static.min.js, see Output bundles.
| File | Purpose |
|---|---|
| etc/build/build.xml | All targets, with a comment block per target |
| etc/build/build.properties | Paths: jscompiler, src.dir (Java sources), war.dir (src/main/webapp), grapheditor.dir, javac.dir (WEB-INF/classes), build.dir (build/), war.name (draw.war) |
etc/build/build.properties.local |
Optional, not committed. Loaded before build.properties, so any property set here wins |
etc/build/compiler.jar |
Closure Compiler |
The dependency chain is merge → app → atlas → integrate → all. javac stands alone, and war depends on app and javac.
| Target | Reads | Writes |
|---|---|---|
merge |
shapes/**/*.js, stencils/**/*.js
|
js/shapes-14-6-5.min.js. Deletes the build/ directory at the end, including a previously built draw.war
|
app |
styles/default.xml, resources/dia.txt, VERSION, mxgraph/mxClient.js, the sources in js/grapheditor, js/diagramly and its subfolders, js/orgchart, the vendored libraries |
js/app.min.js, js/viewer.min.js, js/viewer-static.min.js, js/extensions.min.js, js/orgchart.min.js; leaves etc/build/base.min.js and etc/build/base-viewer.min.js for atlas
|
atlas |
base.min.js, base-viewer.min.js, extensions.min.js, connect/common/js/mxReader.js, js/diagramly/Simple.js
|
js/atlas.min.js, js/atlas-viewer.min.js (intermediate files for integrate) |
integrate |
atlas.min.js, shapes and stencils bundles, etc/integrate/Integrate.js
|
js/integrate.min.js |
all |
Runs integrate, then deletes atlas.min.js and atlas-viewer.min.js
|
|
javac |
src/main/server/java, the jars in WEB-INF/lib
|
WEB-INF/classes (plus a copy of log4j.properties) |
war |
Everything under src/main/webapp after app and javac
|
build/draw.war |
clean |
Deletes WEB-INF/classes, build/, etc/build/base.min.js, etc/build/base-viewer.min.js
|
What app does, in order:
- Writes a small configuration snippet for the viewer bundles that defaults
PROXY_URL,STYLE_PATH,SHAPES_PATH,STENCIL_PATH,DRAW_MATH_URL,GRAPH_IMAGE_PATH,mxImageBasePathandmxBasePathtohttps://viewer.diagrams.net/...unless the page has set them, and setsmxLoadStylesheets = false. - Generates
Graph-Stylesheet.jsfromstyles/default.xml(assigned toGraph.prototype.defaultThemes) andGraph-Resources.jsfromresources/dia.txt(passed tomxResources.parse). - Compiles the intermediate bundles
grapheditor.min.js(Editor.js,EditorUi.js,Sidebar.js,Graph.js,InlineToolbar.js,Format.js,Shapes.js,Actions.js,Menus.js,Toolbar.js,Dialogs.js),sidebar.min.js(everySidebar-*.jspalette) andclient.min.js(deflate/base64.js,diagramly/Init.js,grapheditor/Init.js,mxgraph/mxClient.js). - Builds the viewer bundles, then
extensions.min.jsandorgchart.min.js, thenapp.min.js, replacing@DRAWIO-VERSION@with the contents ofVERSION. - Deletes its temporary files.
Every <jscomp> task uses the same options:
| Option | Value | Effect |
|---|---|---|
compilationLevel |
simple |
Renames local variables and removes whitespace and comments. Properties and global names are kept, which is what lets plugins and PostConfig.js override prototypes by name |
debug |
false |
|
forceRecompile |
true |
Always recompiles |
warning |
${jscomp.warning}, default quiet
|
Prints only errors and the per-task summary. Use ant -Djscomp.warning=default (or verbose) to see warnings |
languageIn / languageOut
|
Not set | The Ant task's defaults for this compiler version apply |
With the defaults, modern syntax such as let, const, arrow functions, class, async and ?? is accepted and transpiled to ES5, and the compiler injects its $jscomp runtime helpers (visible at the top of the compiled code in app.min.js). Syntax newer than v20220502 understands, such as class fields, fails with JSC_PARSE_ERROR and stops the build. The code base itself is written in ES5 style; see Coding conventions.
Vendored libraries that are already minified (pako, DOMPurify, rough.js and so on) are added with <concat> and are never passed through the compiler.
| File | Contents | Loaded by |
|---|---|---|
js/app.min.js |
spin.js, DOMPurify, CryptoJS AES, pako, rough.js, perfect-freehand, client.min.js, grapheditor.min.js, sidebar.min.js, then the draw.io layer: files and storage clients, dialogs, Editor.js, EditorUi.js, ConfigEditor.js, sync, App.js, Menus.js, Pages.js, Minimal.js, Simple.js and more |
bootstrap.js in production mode |
js/shapes-14-6-5.min.js |
Every .js file under shapes/ (and under stencils/, if any) |
App.main before the UI is created; also contained in viewer-static.min.js and integrate.min.js
|
js/stencils.min.js |
All stencil libraries in a compact encoded form. The stencil XML sources are not in this repository, so the public build keeps the committed file |
App.main; Devel.js in development mode; also contained in integrate.min.js and, when built from this repository, in the viewer bundles |
js/extensions.min.js |
Extensions.js (the Lucidchart importer), the VSDX importer, EMF conversion, the GraphML codec, the Miro importer, then JSZip, the binary Visio converter, the ELK layout bundle with ElkLayout.js, the Mermaid bundle, orgchart.min.js, the libavoid router with libavoid-routing.js and LibavoidRouting.js
|
App.main before the UI is created |
js/orgchart.min.js |
The org chart layout libraries plus mxOrgChartLayout.js
|
On demand (also contained in extensions.min.js) |
js/viewer.min.js |
Viewer configuration snippet, spin.js, DOMPurify, pako, rough.js, client.min.js, a subset of the editor (Editor, EditorUi, Graph, Shapes, Actions, DrawioFile, Pages and others), the English UI strings, the default stylesheet and GraphViewer.js; ends by calling window.onDrawioViewerLoad if defined, otherwise GraphViewer.processElements()
|
Pages that embed diagrams, see Embedding |
js/viewer-static.min.js |
viewer.min.js plus shapes-14-6-5.min.js, mxStencilRegistry.allowEval = false and a service worker registration that only runs where Editor.enableServiceWorker is true |
The HTML that the editor exports or generates for embedding (unless DRAWIO_VIEWER_URL names another script), and pages that should not load shape files at runtime |
js/integrate.min.js |
The full editor with the extensions, shapes and stencils, plus Integrate.js, which sets editor defaults for running inside another page and calls window.mxIntegrateCallback if defined (about 20 MB) |
Applications that load the editor into their own page instead of an iframe |
The two viewer bundles differ from the committed files by design. The committed copies are built where the stencil XML is available, so they do not contain the stencil bundle and fetch stencil XML at runtime from STENCIL_PATH, which defaults to https://viewer.diagrams.net/stencils. The public build has no stencil XML, so it appends js/stencils.min.js to both viewer bundles (about 6.8 MB instead of 2.9 MB for viewer.min.js), and a viewer built this way renders all built-in stencils without requests to other hosts.
These files are committed and used as they are. Do not edit the generated ones: your changes would be lost at the next update, and they cannot be rebuilt from this repository.
| Files | Origin |
|---|---|
The bundles in js/elk/, js/mermaid/, js/plantuml/, js/gliffy/ and js/vsd/, js/libavoid-js/libavoid.min.js, and the MathJax bundle in math4/es5/
|
Generated, built outside this repository |
js/stencils.min.js |
Generated from stencil XML that is not in this repository |
mxgraph/mxClient.js |
Generated from mxgraph/src, see the next section |
js/libavoid-js/libavoid-routing.js |
Hand-written source of the routing core, also used by drawio-mcp; see js/libavoid-js/README.md |
js/deflate/pako.min.js, js/sanitizer/purify.min.js, js/cryptojs/aes.min.js, js/spin/spin.min.js, js/rough/rough.min.js, js/freehand/perfect-freehand.js, js/jszip/jszip.min.js, js/jquery/, js/simplepeer/, js/dropbox/, js/onedrive/OneDrive.js, js/orgchart/*.min.js
|
Third-party libraries, copied in by hand. etc/dependencies/package.json records their versions so that dependency security alerts cover them |
Updating a vendored library means replacing the file; there is no package manager. Libraries must be plain scripts that define globals (UMD or IIFE builds, not ES modules). etc/dependencies/dompurify-smoke.js is a smoke test for DOMPurify updates that runs the old and new versions against draw.io's sanitiser configuration; its header explains how to run it.
There are two copies of the graph library:
-
mxgraph/src/holds the sources.mxgraph/src/mxClient.jsis a loader that writes a<script>tag for every source file (mxClient.include(...)). Development mode uses it. -
mxgraph/mxClient.jsis a single minified file with those includes inlined and the version filled in. Theapptarget compiles this file intoclient.min.js.
The public build does not regenerate mxgraph/mxClient.js. A change under mxgraph/src therefore shows up with ?dev=1 but not in any bundle you build. Keep changes to graph behaviour in the editor layers instead: override the mx* prototype methods from js/grapheditor, js/diagramly or a plugin, which is how draw.io customises mxGraph itself (see Architecture).
A new file has to be registered twice: once for development mode and once for the build. Order matters in both places, because files only see what was loaded before them.
-
Development mode. Add an
mxscript(...)line to js/diagramly/Devel.js after the files it depends on:mxscript(drawDevUrl + 'js/diagramly/MyFeature.js');
Files under
mxgraph/srcare listed inmxgraph/src/mxClient.jsinstead, but see the limitation above. -
Build. Add a
<file>element to the matching<jscomp>block inetc/build/build.xml:Kind of file Block(s) in the apptargetjs/grapheditor/*.jsThe grapheditor.min.jsblock; also the viewer block (.tmp1.js, step 7) if the viewer needs itjs/diagramly/sidebar/Sidebar-*.jsThe sidebar.min.jsblockjs/diagramly/*.jsfor the editorThe final application block (step 10) that becomes app.min.js, and thebase.min.jsblock before it, which feedsatlasandintegrate; also the viewer block if the viewer needs itImport and export code The extensions.min.jsblockA pre-minified third-party library A <filelist>in the<concat>that buildsapp.min.js(andbase.min.js, andbase-viewer.min.jsif the viewer needs it), not a<jscomp>blockFor example, for a file the editor needs after
App.js:<sources dir="${war.dir}/js/diagramly"> <file name="App.js" /> <file name="MyFeature.js" /> <file name="Menus.js" /> ...
-
Run
ant appand test both/?dev=1and/.
Shape files are different: every .js file under shapes/ is picked up by merge automatically, and development mode loads them on demand through the mxStencilRegistry.libraries table in js/diagramly/Editor.js. See Shapes and stencils. A new sidebar palette also needs registering in the sidebar code, see Extending the editor.
ant war runs app and javac and zips the whole of src/main/webapp into build/draw.war. The archive contains:
- every static file of the web application, including the development sources, templates, resources and images,
-
WEB-INF/web.xml, which maps the servlets, -
WEB-INF/classeswith the compiled servlets fromsrc/main/server/java/com/mxgraph/online, -
WEB-INF/libwith the servlet API and the libraries the servlets use, - placeholder files such as
WEB-INF/google_client_id, which the OAuth servlets read their credentials from.
Note that war does not run atlas or integrate, so the archive contains whatever integrate.min.js is in js/.
The servlets use the javax.servlet API. Which endpoints they provide, and which endpoints the client calls that are not in the .war, is listed in Self-hosting.
For each release tag (v*) the war.yml workflow runs ant war and attaches draw.war to the GitHub release. The Docker image builds the same way from a clone of this repository.
-
No stencil XML. If any
.xmlfile exists undersrc/main/webapp/stencils,mergetries to convert the stencil XML with a helper class that is not in this repository and fails withCould not find Xml2Js. Ship custom stencils as a custom library or as JavaScript shapes instead, see Shapes and stencils. - mxGraph sources are not rebuilt, see above.
-
The service worker is not regenerated.
service-worker.jslists the precached files with checksums of the released bundles, and nothing in the public build updates it. See Self-hosting. -
/embed.jsis mapped inWEB-INF/web.xmlto a servlet class that is not part of this repository, so requests to it fail in the.war. - Bundles built elsewhere (ELK, Mermaid, PlantUML, Gliffy, binary Visio, libavoid, MathJax) cannot be rebuilt from this repository; updated copies arrive with draw.io releases.
Describes the dev branch of jgraph/drawio as of release 32.3.0 (October 2026). Internal JavaScript APIs change between releases; check the code of the version you use. · Questions: Discussions · Bugs: Issues · Vulnerabilities: report privately · User docs: drawio.com/docs
Get started
Concepts
Guides
- Self-hosting
- Configuration
- Storage backends
- OneDrive app registration
- Embedding
- Diagrams in GitHub
- Plugins
- Extending the editor
- Shapes and stencils
- Import and export
- Desktop app
- Internationalization
Reference
Project
Elsewhere