Draw.io is an open-source diagramming tool that replaces Lucidchart and Visio with a free, client-side editor that saves directly to your own storage.
Draw.io is a diagramming and flowchart application that runs directly in any modern web browser or as a desktop program. Its defining property is a storage-agnostic architecture: users create and edit diagrams without registering an account or routing proprietary data through remote servers. All processing happens client-side, saving files directly to local storage, connected cloud drives, or developer repositories.
Lucidchart charges eight to nine dollars per user every month on individual plans, and more per seat for teams. Its free tier restricts accounts to three editable documents and sixty objects per canvas, pushing casual users onto a subscription just to finish a basic flowchart or process map. Draw.io eliminates that recurring cost entirely. Whether opened in a browser or installed on a desktop, it has no paid tiers, no per-user invoices, and no artificial caps on document count or canvas elements.
The difference comes down to infrastructure. Lucidchart bundles its subscription with central cloud storage, live multi-cursor co-editing, and automated data integrations. Draw.io skips proprietary cloud hosting: diagrams save directly to local disk, Google Drive, Microsoft OneDrive, or GitHub. While you give up simultaneous live collaboration across an active team, you remove subscription overhead for people who only diagram occasionally. Migration is straightforward, with direct import for Microsoft Visio (.vsdx) and Lucidchart files so past work remains accessible.
.vsdx files, letting users collaborate across organizations without purchasing Visio.Is Draw.io completely free for commercial use? Yes. Draw.io is free for personal and commercial projects, with no paid subscription tiers or object limits.
Draw.io vs Lucidchart — which should non-technical teams choose? Choose Lucidchart for real-time multiplayer whiteboarding and cloud-managed permissions. Choose Draw.io to avoid per-seat subscription fees while retaining full ownership of your diagram files.
Can Draw.io open and edit Microsoft Visio files?
Yes. Draw.io imports and exports standard Microsoft Visio .vsdx files without requiring a Visio license.
Draw.io is an ideal choice for teams seeking capable diagramming without recurring per-seat fees; it is not suited for groups requiring simultaneous live multiplayer editing. Active development with updates pushed as recently as September 2026 and an Apache-2.0 license for the core code make it a dependable staple for cost-conscious diagramming.
We started this exact setup from scratch in a clean Linux machine on Nov 2, 2026 and checked it through Draw.io's own API: every check passed. Recipes are re-checked regularly and removed if they stop working.
mkdir -p draw-io && cd draw-io
curl -fsSL https://open-source.store/tools/draw-io/compose.yml -o compose.ymlcat > .env <<EOF
DRAWIO_SERVER_URL=http://localhost:8080/
EOFDRAWIO_SERVER_URL — Public URL where Draw.io is accessed, ending with a trailing slash.docker compose up -dservices:
drawio:
image: jgraph/drawio:32.6.9
restart: unless-stopped
ports:
- "8080:8080"
environment:
DRAWIO_SERVER_URL: ${DRAWIO_SERVER_URL}
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/ || exit 1"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
Ubuntu 24.04 · Apple container, Docker 29.1.3, Compose 2.40.3+ds1-0ubuntu1~24.04.1. Images pulled in 45 s: jgraph/drawio:32.6.9.
Go, gRPC and Protobuf done right, LLM agents in production, and the hard parts of shipping a first product.
Show that Draw.io is listed as an open-source alternative. Paste into your README:
Based on the upstream setup. Official compose. Image pinned to 32.6.9; port 8443 removed; healthcheck updated to localhost; DRAWIO_SERVER_URL moved to .env.
drawio-1 | 2026-11-02T07:48:54.841051046Z at com.mxgraph.online.ExportProxyServlet.doRequest(Unknown Source) drawio-1 | 2026-11-02T07:48:54.841052504Z at com.mxgraph.online.ExportProxyServlet.doGet(Unknown Source) drawio-1 | 2026-11-02T07:48:54.841053171Z at javax.servlet.http.HttpServlet.service(HttpServlet.java:529) drawio-1 | 2026-11-02T07:48:54.841053754Z at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) drawio-1 | 2026-11-02T07:48:54.841054296Z at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:201) drawio-1 | 2026-11-02T07:48:54.841054921Z at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:146) drawio-1 | 2026-11-02T07:48:54.841055504Z at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:57) drawio-1 | 2026-11-02T07:48:54.841056046Z at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:170) drawio-1 | 2026-11-02T07:48:54.841056671Z at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:146) drawio-1 | 2026-11-02T07:48:54.841057254Z at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) drawio-1 | 2026-11-02T07:48:54.841057796Z at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:88) drawio-1 | 2026-11-02T07:48:54.841058337Z at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:539) drawio-1 | 2026-11-02T07:48:54.841058921Z at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:129) drawio-1 | 2026-11-02T07:48:54.841059462Z at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:86) drawio-1 | 2026-11-02T07:48:54.841060004Z at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:764) drawio-1 | 2026-11-02T07:48:54.841060546Z at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:71) drawio-1 | 2026-11-02T07:48:54.841061087Z at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:350) drawio-1 | 2026-11-02T07:48:54.841068171Z at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:412) drawio-1 | 2026-11-02T07:48:54.841068754Z at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:71) drawio-1 | 2026-11-02T07:48:54.841069337Z at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1345) drawio-1 | 2026-11-02T07:48:54.841069921Z at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:2255) drawio-1 | 2026-11-02T07:48:54.841078671Z at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:74) drawio-1 | 2026-11-02T07:48:54.841107629Z at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:974) drawio-1 | 2026-11-02T07:48:54.841114296Z at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:492) drawio-1 | 2026-11-02T07:48:54.841115379Z at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:80) drawio-1 | 2026-11-02T07:48:54.841116212Z at java.base/java.lang.Thread.run(Thread.java:829) drawio-1 | 2026-11-02T07:48:54.845915796Z java.lang.Exception: EXPORT_URL not set or invalid drawio-1 | 2026-11-02T07:48:54.845928087Z at com.mxgraph.online.ExportProxyServlet.doRequest(Unknown Source) drawio-1 | 2026-11-02T07:48:54.845929212Z at com.mxgraph.online.ExportProxyServlet.doGet(Unknown Source) drawio-1 | 2026-11-02T07:48:54.845929796Z at javax.servlet.http.HttpServlet.service(HttpServlet.java:529) drawio-1 | 2026-11-02T07:48:54.845930337Z at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) drawio-1 | 2026-11-02T07:48:54.845930879Z at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:201) drawio-1 | 2026-11-02T07:48:54.845931504Z at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:146) drawio-1 | 2026-11-02T07:48:54.845932087Z at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:57) drawio-1 | 2026-11-02T07:48:54.845932587Z at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:170) drawio-1 | 2026-11-02T07:48:54.845933171Z at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:146) drawio-1 | 2026-11-02T07:48:54.845933712Z at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) drawio-1 | 2026-11-02T07:48:54.845934254Z at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:88) drawio-1 | 2026-11-02T07:48:54.845934754Z at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:539) drawio-1 | 2026-11-02T07:48:54.845935296Z at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:129) drawio-1 | 2026-11-02T07:48:54.845936129Z at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:86) drawio-1 | 2026-11-02T07:48:54.845936671Z at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:764) drawio-1 | 2026-11-02T07:48:54.845937212Z at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:71) drawio-1 | 2026-11-02T07:48:54.845937754Z at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:350) drawio-1 | 2026-11-02T07:48:54.845945129Z at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:412) drawio-1 | 2026-11-02T07:48:54.845945754Z at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:71) drawio-1 | 2026-11-02T07:48:54.845946296Z at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1345) drawio-1 | 2026-11-02T07:48:54.845946879Z at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:2255) drawio-1 | 2026-11-02T07:48:54.845947421Z at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:74) drawio-1 | 2026-11-02T07:48:54.845947921Z at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:974) drawio-1 | 2026-11-02T07:48:54.845948712Z at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:492) drawio-1 | 2026-11-02T07:48:54.845949254Z at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:80) drawio-1 | 2026-11-02T07:48:54.845949796Z at java.base/java.lang.Thread.run(Thread.java:829) drawio-1 | 2026-11-02T07:48:56.843621088Z java.lang.Exception: EXPORT_URL not set or invalid drawio-1 | 2026-11-02T07:48:56.843685922Z at com.mxgraph.online.ExportProxyServlet.doRequest(Unknown Source) drawio-1 | 2026-11-02T07:48:56.843688088Z at com.mxgraph.online.ExportProxyServlet.doGet(Unknown Source) drawio-1 | 2026-11-02T07:48:56.843690588Z at javax.servlet.http.HttpServlet.service(HttpServlet.java:529) drawio-1 | 2026-11-02T07:48:56.843709172Z at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) drawio-1 | 2026-11-02T07:48:56.843710005Z at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:201) drawio-1 | 2026-11-02T07:48:56.843710838Z at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:146) drawio-1 | 2026-11-02T07:48:56.843713213Z at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:57) drawio-1 | 2026-11-02T07:48:56.843723880Z at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:170) drawio-1 | 2026-11-02T07:48:56.843736422Z at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:146) drawio-1 | 2026-11-02T07:48:56.843738297Z at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) drawio-1 | 2026-11-02T07:48:56.843768463Z at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:88) drawio-1 | 2026-11-02T07:48:56.843769130Z at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:539) drawio-1 | 2026-11-02T07:48:56.843769672Z at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:129) drawio-1 | 2026-11-02T07:48:56.843770255Z at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:86) drawio-1 | 2026-11-02T07:48:56.843772338Z at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:764) drawio-1 | 2026-11-02T07:48:56.843783172Z at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:71) drawio-1 | 2026-11-02T07:48:56.843791547Z at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:350) drawio-1 | 2026-11-02T07:48:56.843793297Z at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:412) drawio-1 | 2026-11-02T07:48:56.843793838Z at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:71) drawio-1 | 2026-11-02T07:48:56.843816213Z at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1345) drawio-1 | 2026-11-02T07:48:56.843817005Z at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:2255) drawio-1 | 2026-11-02T07:48:56.843833797Z at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:74) drawio-1 | 2026-11-02T07:48:56.843868797Z at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:974) drawio-1 | 2026-11-02T07:48:56.843871797Z at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:492) drawio-1 | 2026-11-02T07:48:56.843872505Z at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:80) drawio-1 | 2026-11-02T07:48:56.843873047Z at java.base/java.lang.Thread.run(Thread.java:829) drawio-1 | 2026-11-02T07:48:56.843880713Z java.lang.Exception: EXPORT_URL not set or invalid drawio-1 | 2026-11-02T07:48:56.843892797Z at com.mxgraph.online.ExportProxyServlet.doRequest(Unknown Source) drawio-1 | 2026-11-02T07:48:56.843956005Z at com.mxgraph.online.ExportProxyServlet.doGet(Unknown Source) drawio-1 | 2026-11-02T07:48:56.843960130Z at javax.servlet.http.HttpServlet.service(HttpServlet.java:529) drawio-1 | 2026-11-02T07:48:56.843960797Z at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) drawio-1 | 2026-11-02T07:48:56.843961338Z at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:201) drawio-1 | 2026-11-02T07:48:56.843961963Z at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:146) drawio-1 | 2026-11-02T07:48:56.843962505Z at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:57) drawio-1 | 2026-11-02T07:48:56.843963088Z at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:170) drawio-1 | 2026-11-02T07:48:56.843963672Z at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:146) drawio-1 | 2026-11-02T07:48:56.843964213Z at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:165) drawio-1 | 2026-11-02T07:48:56.843964755Z at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:88) drawio-1 | 2026-11-02T07:48:56.843965297Z at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:539) drawio-1 | 2026-11-02T07:48:56.843965922Z at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:129) drawio-1 | 2026-11-02T07:48:56.843966547Z at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:86) drawio-1 | 2026-11-02T07:48:56.843967047Z at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:764) drawio-1 | 2026-11-02T07:48:56.843969547Z at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:71) drawio-1 | 2026-11-02T07:48:56.843970213Z at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:350) drawio-1 | 2026-11-02T07:48:56.843970797Z at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:412) drawio-1 | 2026-11-02T07:48:56.843971338Z at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:71) drawio-1 | 2026-11-02T07:48:56.843971880Z at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1345) drawio-1 | 2026-11-02T07:48:56.843972463Z at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:2255) drawio-1 | 2026-11-02T07:48:56.843973005Z at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:74) drawio-1 | 2026-11-02T07:48:56.843973547Z at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:974) drawio-1 | 2026-11-02T07:48:56.843974088Z at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:492) drawio-1 | 2026-11-02T07:48:56.843974588Z at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:80) drawio-1 | 2026-11-02T07:48:56.843975130Z at java.base/java.lang.Thread.run(Thread.java:829) drawio-1 | 2026-11-02T07:49:04.819742300Z 02-Nov-2026 07:49:04.817 INFO [http-nio-8080-exec-20] org.apache.coyote.http11.Http11Processor.service Error parsing HTTP request header drawio-1 | 2026-11-02T07:49:04.819770550Z Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level. drawio-1 | 2026-11-02T07:49:04.819774009Z java.lang.IllegalArgumentException: Invalid character found in the request target [/content/crx/de/setPreferences.jsp;%0A.html?language=en&keymap=<svg/onload=confirm(document.domain);>//a ]. The valid characters are defined in RFC 7230 and RFC 3986 drawio-1 | 2026-11-02T07:49:04.819777259Z at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:485) drawio-1 | 2026-11-02T07:49:04.819779509Z at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:280) drawio-1 | 2026-11-02T07:49:04.819781300Z at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:71) drawio-1 | 2026-11-02T07:49:04.819782925Z at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1345) drawio-1 | 2026-11-02T07:49:04.819784550Z at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:2255) drawio-1 | 2026-11-02T07:49:04.819786175Z at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:74) drawio-1 | 2026-11-02T07:49:04.819787759Z at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:974) drawio-1 | 2026-11-02T07:49:04.819789342Z at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:492) drawio-1 | 2026-11-02T07:49:04.819790967Z at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:80) drawio-1 | 2026-11-02T07:49:04.819792592Z at java.base/java.lang.Thread.run(Thread.java:829)