npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

d2-to-drawio

v1.0.1

Published

Convert D2 diagrams to editable draw.io / diagrams.net files (.drawio XML) from the CLI or Node.js

Downloads

47

Readme

d2-to-drawio

npm version CI license: MIT node

Convert D2 diagrams to draw.io files: keep authoring diagrams as code in D2, and hand fully editable drawio / diagrams.net files to everyone else. Shapes, containers, edges, styles, and positions all come across as native draw.io elements, not as a pasted image.

npx d2-to-drawio examples/basic.d2 -o basic.drawio

What you get

direction: right

user: Visitor { shape: person }
app: "Web App"
db: "Postgres" { shape: cylinder }

user -> app: "browses"
app -> db: "reads / writes"
npx d2-to-drawio examples/basic.d2 -o basic.drawio

The result, opened in draw.io, every element selectable and editable:

basic example rendered in draw.io

A richer example with containers, a queue, crow's foot cardinality, and tooltips (source):

microservices example rendered in draw.io

Open the committed outputs directly in your browser:

Why this exists

Plenty of teams standardize on draw.io and Confluence for documentation, while the engineers drawing the systems would rather write diagrams as code, version them, and review them in pull requests. Exporting D2 to SVG or PNG hands the team a static picture nobody can edit; switching the whole team to D2 rarely happens. This tool removes that one-way door: engineers keep the .d2 source of truth, everyone else gets a native .drawio file they can open, edit, and paste into Confluence.

AI-generated diagrams that stay editable

There is a second door this opens: diagrams drafted by an AI. Language models like Claude and ChatGPT write D2 fluently, because D2 is compact text and its layout is automatic: the model writes api -> queue: enqueue and never has to decide where anything goes. What models are consistently bad at is spatial placement, which is exactly what generating draw.io XML directly demands (hundreds of hand-invented x/y coordinates that end up overlapping). The workflow this enables:

  1. Ask your model: "Describe my architecture as a D2 diagram" and save the answer as arch.d2.
  2. npx d2-to-drawio arch.d2 -o arch.drawio (a real layout engine, not the model, places everything).
  3. Open it in draw.io and fix the 10 percent a human should fix, by dragging.

The AI does the structure, the layout engine does the geometry, you keep an editable file. None of the three steps fights the other.

Quick start

npm install -g d2-to-drawio
d2-to-drawio diagram.d2 -o diagram.drawio

Or without installing:

npx d2-to-drawio diagram.d2 -o diagram.drawio

Or from stdin to stdout:

cat diagram.d2 | d2-to-drawio > diagram.drawio

CLI reference

Usage: d2-to-drawio [options] [input.d2]

Reads from the input file, or from stdin when no file is given (or "-").
Writes to --output, or to stdout.

Options:
  -o, --output <file>   write the .drawio XML to a file instead of stdout
      --layout <name>   layout engine: dagre (default) or elk
      --theme <id>      D2 theme id (default 0)
      --waypoints       preserve D2 edge routes as fixed waypoints
      --strict          fail when input uses features that would degrade
  -q, --quiet           suppress warnings on stderr
  -h, --help            show this help
  -v, --version         print the version

Behavior notes:

  • @imports resolve automatically: for file input, every .d2 under the input file's directory is available to the compiler; for stdin, imports resolve against the current directory.
  • Unsupported D2 features never crash a conversion. Each degrades to the closest visual and prints one warning line to stderr. --strict turns those warnings into a failing exit instead.
  • By default draw.io re-routes edges orthogonally, which keeps them fully editable. --waypoints pins d2's exact computed routes instead.
  • Exit codes: 0 success, 1 conversion or input error, 2 usage error.

Library API

import { convert, convertFile, dispose } from 'd2-to-drawio';

const xml = await convert('a -> b: hello');
// or, resolving imports relative to the file:
const xml2 = await convertFile('diagram.d2', { layout: 'elk' });

await dispose();
  • convert(d2Source, options) returns a Promise of the .drawio XML string.
  • convertFile(inputPath, options) reads the file and feeds sibling .d2 files to the compiler so relative imports work.
  • options: layout ('dagre' | 'elk'), themeID (number), strict (boolean), waypoints (boolean), onWarning (callback receiving {code, message}), fsMap/inputPath (virtual filesystem for imports when using convert).
  • dispose() releases the compiler's worker thread. Call it when done, or your process will stay alive. The next convert after a dispose transparently starts a fresh engine.
  • Errors: malformed D2 rejects with D2SyntaxError (message carries file:line:column); strict-mode degradations reject with UnsupportedFeatureError (carrying the warning list).

Output is deterministic: identical input produces byte-identical output, so generated files diff cleanly in version control.

Feature support

The full, fixture-backed matrix lives in docs/FEATURE-MATRIX.md. Summary:

| Area | Support | |---|---| | Shape catalog (rectangle, square, page, parallelogram, document, cylinder, queue, package, step, callout, stored_data, person, diamond, oval, circle, hexagon, cloud, image, text) | Full | | Containers, any nesting depth, grid diagrams | Full | | Connections: -> <- <-> --, chains, parallel edges, self-loops | Full | | Arrowheads incl. crow's foot ER markers, arrowhead labels | Full | | Styles: fill, stroke, stroke-width, stroke-dash, opacity, shadow, fonts, bold/italic/underline | Full | | Themes: all 20 official palettes | Full | | Compiler-level features: vars, globs, classes, imports, overrides, null | Full | | Boards (layers, scenarios, steps) | Full, one draw.io page per board | | Tooltips and links | Full | | sql_table, class (UML) | Partial: formatted single shapes, not row-by-row cells | | Sequence diagrams | Partial: exact d2 geometry, but fixed (does not re-route) | | Markdown / LaTeX / code labels | Partial: plain text / MathJax / monospace box | | multiple, 3d, double-border, fill-pattern, animated, sketch | Unsupported, warned |

Limitations

  • The compiler dependency (@terrastruct/d2, the official WASM build of D2) is around 60 MB installed and takes a couple of seconds to start. One-shot CLI runs pay that startup; batch conversions should use the library API, which reuses the engine across calls.
  • sql_table and class shapes are single shapes with formatted labels. Editing individual rows as draw.io table cells is on the roadmap.
  • Sequence diagram messages and lifelines keep d2's exact geometry and will not re-route if you move the actors.
  • Links between D2 boards (link: layers.x) do not become page links in draw.io yet.
  • The TALA layout engine is not part of the embedded compiler; dagre and elk are available.

How it works

The official D2 compiler (as a WASM build) parses the source and runs the real layout engine, producing fully positioned shapes and routed connections. This tool walks that output, rebuilds the container tree, and translates shapes, styles, and theme colors into draw.io's mxGraph cell model. It then emits deterministic, uncompressed .drawio XML that draw.io opens like any hand-drawn file.

Roadmap

Only things actually planned:

  • Native draw.io table cells for sql_table and class shapes.
  • draw.io sketch style for D2 sketch mode.
  • Page links for D2 board links.
  • Icons on regular shapes (currently only shape: image carries an image).

Related projects

As of July 2026 this is the only dedicated D2 to draw.io converter I am aware of. Related tools:

  • D2: the diagram language itself.
  • draw.io / diagrams.net: the editor this tool targets.
  • @whitebite/diagram-converter: a universal multi-format diagram converter whose published build includes a D2 parser and drawio generator via a shared intermediate representation. A generalist; this tool goes deeper on D2 fidelity (layout preservation, themes, special shapes, degradation warnings).
  • mmd2drawio: the same idea for Mermaid.
  • The SVG detour: D2 can export SVG that draw.io imports as a static image. Works, but nothing is editable; that gap is the point of this project (see also jgraph/drawio#3764, an open request for D2 input in draw.io itself).

Contributing

See CONTRIBUTING.md. The short version: fixture first, then the mapping code, then a row in the feature matrix. Bug reports with a minimal .d2 snippet are gold.

License

MIT. The @terrastruct/d2 dependency is MPL-2.0, used unmodified.