Skip to content

Getting Started

David Benson edited this page Oct 7, 2026 · 1 revision

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.

Prerequisites

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.

Clone the repository

git clone --depth 1 https://github.com/jgraph/drawio.git
cd drawio

The 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 the web application

Serve src/main/webapp with any static web server:

cd src/main/webapp
python3 -m http.server 8080

Then 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.html as a file:// URL does not work, because the language files and other resources are loaded with XMLHttpRequest.
  • A blank "Untitled Diagram" opens straight away. Init.js sets splash=0 unless the configuration sets showSplashOnStart (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). Add ui=min or ui=simple to try the other themes in production mode.

Production mode and development 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.

What to expect in development mode

Development mode in this repository differs from production in a few ways that are easy to mistake for bugs:

  • One 404 is expected. Devel.js requests js/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.js loads js/diagramly/Simple.js only when window.DRAWIO_PUBLIC_BUILD is not set, and this repository's PreConfig.js sets it. ui=simple and ui=sketch fall back to the classic UI in development mode; they work in production mode, where Simple.js is part of app.min.js.
  • The version reads @DRAWIO-VERSION@, for example in the Help menu. The build replaces it.
  • A Content-Security-Policy is active. Devel.js adds 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 in Devel.js while you develop.
  • Stencils come from the bundle. The stencil XML sources are not in this repository, so Devel.js loads js/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.

What works without any keys

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.

Caches and the service worker

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.html on the same host (http://localhost:8080/clear.html), which unregisters every service worker of the origin,
  • load ?offline=0&enableSW=1, which makes App.main unregister it and show "Cache cleared".

Offline use of a self-hosted instance has further limits, see Self-hosting.

Make your first change

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.

  1. 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);
    		};
    	};
    })();
  2. Reload http://localhost:8080/?dev=1. Open the Help menu: Hello World is the last item, and clicking it shows the alert.

  3. 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.init builds 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 is mxResources.get(key), which is why the block adds a string with mxResources.parse. For a translatable label, add helloWorld=Hello World to resources/dia.txt instead (see Internationalization).
  • this.get('help') returns the Menu object. Its funct fills 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.

Publishing a fork with GitHub Pages

Because the bundles are committed, a fork runs on GitHub Pages without a build:

  1. Fork jgraph/drawio.
  2. In the fork, open Settings > Pages and deploy from the dev branch, root folder.
  3. 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.

Next steps

  • 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

See also

Clone this wiki locally