Repository navigation
Getting Started
This page takes you from a fresh clone to a running editor and a first code change you can see. It is for developers who want to run, debug or modify draw.io from source; no build tools are needed until you want to produce minified bundles.
| You need | For |
|---|---|
| Git | Cloning the repository |
| A current browser (supported browsers) | Running the editor |
| Any static web server (Python 3 is used below) | Serving src/main/webapp over HTTP |
| JDK and Apache Ant | Only for rebuilding the minified bundles or the .war, see Building
|
There is no npm install and no bundler to run first. The application is plain browser JavaScript, and the minified bundles it runs from are committed to the repository.
git clone --depth 1 https://github.com/jgraph/drawio.git
cd drawioThe default branch, dev, holds the latest release. The full history is large (well over a gigabyte), so a shallow clone is the quickest way to start; you can still build and run everything from it.
Serve src/main/webapp with any static web server:
cd src/main/webapp
python3 -m http.server 8080Then open one of:
| URL | Mode |
|---|---|
http://localhost:8080/ |
Production mode: runs the committed minified bundles |
http://localhost:8080/?dev=1 |
Development mode: loads the unminified sources one file at a time |
Notes:
- All paths in the application are relative, so you can also serve the repository root and open
http://localhost:8080/src/main/webapp/index.html(or.../src/main/webapp/?dev=1). This is the layout GitHub Pages uses. - Always use HTTP. Opening
index.htmlas afile://URL does not work, because the language files and other resources are loaded withXMLHttpRequest. - A blank "Untitled Diagram" opens straight away. Init.js sets
splash=0unless the configuration setsshowSplashOnStart(see Configuration). - On your own host you get the classic UI with the menu bar (File, Edit, View, Arrange, Extras, Help) at any window size; the simpler UI is only chosen automatically on small or touch screens on app.diagrams.net (
App.isSimpleThemePreferred). Addui=minorui=simpleto try the other themes in production mode.
bootstrap.js parses the URL into the global urlParams object and chooses the mode with a single check, urlParams['dev'] == '1'. There is no host restriction: ?dev=1 works on any host, port and path.
Production (/) |
Development (?dev=1) |
|
|---|---|---|
| Scripts loaded |
js/PreConfig.js, js/app.min.js, js/PostConfig.js, then shapes-14-6-5.min.js, stencils.min.js and extensions.min.js before the UI starts |
About 300 individual files: PreConfig.js, both Init.js files, mxgraph/src/mxClient.js (which loads every file under mxgraph/src), then everything listed in Devel.js, then PostConfig.js
|
| Your source edits | Not visible until you rebuild with ant (Building) |
Visible on the next reload |
| Default stylesheet | Compiled into app.min.js from styles/default.xml
|
styles/default.xml is loaded at runtime |
| UI strings |
resources/dia*.txt loaded at runtime |
Same |
Shape files in shapes/
|
Bundled in shapes-14-6-5.min.js
|
Loaded on demand through mxStencilRegistry.libraries
|
EditorUi.VERSION |
The release number from VERSION
|
The placeholder @DRAWIO-VERSION@
|
In production mode, PreConfig.js and PostConfig.js are only requested on hosts other than *.draw.io and *.diagrams.net, which is every host you will run it on. In development mode they are always loaded. Both files are the hooks for configuring an instance, see Self-hosting.
Development mode in this repository differs from production in a few ways that are easy to mistake for bugs:
-
One 404 is expected.
Devel.jsrequestsjs/diagramly/vsdx/mxVsdxCanvas2D.js, which is not part of this repository (VSDX export is not included). Nothing else depends on it. -
Only the classic and minimal themes are available.
Devel.jsloadsjs/diagramly/Simple.jsonly whenwindow.DRAWIO_PUBLIC_BUILDis not set, and this repository'sPreConfig.jssets it.ui=simpleandui=sketchfall back to the classic UI in development mode; they work in production mode, whereSimple.jsis part ofapp.min.js. -
The version reads
@DRAWIO-VERSION@, for example in the Help menu. The build replaces it. -
A Content-Security-Policy is active.
Devel.jsadds a CSP<meta>tag (including'unsafe-eval', which the on-demand shape loading needs). Requests to origins that are not in that policy are blocked, for example a service of your own on another port. Add the origin to the policy inDevel.jswhile you develop. -
Stencils come from the bundle. The stencil XML sources are not in this repository, so
Devel.jsloadsjs/stencils.min.js.
Two URL parameters help while developing: test=1 turns on the EditorUi.debug console output, and dev-tooltips=1 (development mode only) adds cell IDs and geometry to the tooltips. See Debugging for more.
A local instance needs no accounts or API keys for most of the editor.
| Works out of the box | Needs more setup |
|---|---|
| Editing, all shape libraries, templates, layouts | Google Drive, OneDrive, GitHub and GitLab storage: your own OAuth apps plus the token servlets of the .war, see Storage backends
|
| Device storage (open, save, download) and browser storage | Real-time collaboration: PreConfig.js sets sync=manual, and the services it needs are not part of this repository |
| Export to PNG, JPEG, SVG, HTML and XML in the browser | Server-side export: PreConfig.js sets EXPORT_URL = null, so PDF export uses the browser's print dialog |
Import of .vsdx, Mermaid, PlantUML, Gliffy and other formats that are converted in the browser |
Icon search: PostConfig.js sets ICONSEARCH_PATH and ICON_SERVICE_PATH to null
|
MathJax typesetting (served from math4/es5) |
Opening files or images from other hosts, apart from a few known CORS-enabled ones (see Debugging): needs the /proxy servlet, see Self-hosting
|
By default the editor still loads the Google API script from apis.google.com and initialises the OneDrive client, even though they cannot sign in without your own app registrations. Add ?gapi=0&od=0 to the URL, or disable them for everyone in PreConfig.js as shown in Self-hosting.
Most "my change does not show up" problems while iterating come from caching.
The HTTP cache. Simple static servers such as python3 -m http.server send a Last-Modified header but no Cache-Control, so the browser may reuse a cached copy of a file you have just edited (this happens with PreConfig.js in particular). Tick Disable cache in the Network tab of the browser's developer tools and keep the tools open while you work, or use a hard reload.
The service worker. draw.io only registers its service worker where Editor.enableServiceWorker is true. In Editor.js that is on *.diagrams.net and *.draw.io, or on any host when the URL contains offline=1 or enableSW=1; pwa=0 turns it off everywhere. On localhost without those parameters no service worker is involved.
With ?offline=1 the browser tries to install the committed service-worker.js, which normally fails on your own host (see Self-hosting). A service worker that did install for your origin, for example one of your own, answers requests for the precached files (index.html, js/app.min.js, the other bundles) from its cache. Developer tools list it under Application > Service workers. To remove it, do one of:
- click Unregister in developer tools,
- open
clear.htmlon the same host (http://localhost:8080/clear.html), which unregisters every service worker of the origin, - load
?offline=0&enableSW=1, which makesApp.mainunregister it and show "Cache cleared".
Offline use of a self-hosted instance has further limits, see Self-hosting.
This example adds a Hello World item to the Help menu. It uses the same pattern the bundled plugins use: register an action, then wrap the menu's build function.
-
Append this block to the end of js/diagramly/Menus.js:
// Adds Help > Hello World (function() { var menusInit = Menus.prototype.init; Menus.prototype.init = function() { menusInit.apply(this, arguments); var editorUi = this.editorUi; mxResources.parse('helloWorld=Hello World'); editorUi.actions.addAction('helloWorld', function() { editorUi.alert('Hello from my build of draw.io'); }); var menu = this.get('help'); var oldFunct = menu.funct; menu.funct = function(menu, parent) { oldFunct.apply(this, arguments); editorUi.menus.addMenuItems(menu, ['-', 'helloWorld'], parent); }; }; })();
-
Reload
http://localhost:8080/?dev=1. Open the Help menu: Hello World is the last item, and clicking it shows the alert. -
To see the change in production mode, rebuild the bundles and reload
http://localhost:8080/(with the cache disabled):cd etc/build ant app
What the code does:
-
Menus.prototype.initbuilds all menus when the UI is created. The block wraps it, so it runs after the existing definitions, including the draw.io override earlier in the same file. -
editorUi.actions.addAction(key, funct)registers an action. The menu label ismxResources.get(key), which is why the block adds a string withmxResources.parse. For a translatable label, addhelloWorld=Hello Worldtoresources/dia.txtinstead (see Internationalization). -
this.get('help')returns theMenuobject. Itsfunctfills the menu each time it opens; the wrapper calls the original and appends a separator and the new item.
The same code works without touching the core files as a plugin passed to Draw.loadPlugin, see Plugins. Many defaults (fonts, colours, libraries, styles) can be changed without any code through DRAWIO_CONFIG in PreConfig.js, see Configuration. A new source file must also be registered in two places, see Building.
Because the bundles are committed, a fork runs on GitHub Pages without a build:
- Fork jgraph/drawio.
- In the fork, open Settings > Pages and deploy from the
devbranch, root folder. - Open
https://<your-user>.github.io/drawio/src/main/webapp/index.html.
This is how jgraph.github.io/drawio/src/main/webapp/index.html is published. The editor works fully, but without the cloud storage integrations, which need server-side code and your own OAuth apps. Commit rebuilt bundles if you want your source changes to appear in production mode there. More hosting options are in Self-hosting.
- Architecture: the layers, the startup sequence and how the pieces fit
- Code map: where the code for each feature lives
-
Building: rebuilding the bundles and the
.war - Debugging: breakpoints, logging and common problems
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