A free, open-source, entirely client-side Sankey diagram builder. Upload a
CSV/TSV, or start from one of five bundled sample datasets, style it with a
full set of layout/label/flow/node controls, and save your work locally as a
.skd file — no server, no account, no signup, and no data ever leaves the
browser.
This is a trimmed-down edition of the rendering engine behind SankeyBUILDER.org — the full hosted product adds account-based diagram storage, Google Sheet / API-push live data sources, webhooks, and AI-generated flow analysis (Flow Intelligence). None of that is here; this repo is just the diagram engine itself, free for anyone to drop into their own project. Want the full version instead of building it out yourself? Check out sankeybuilder.org.
sankey_builder.html— the page shell: toolbar, tabs (Layout / Labels / Flow / Node / Data), and the modals the JS drives.sankey_builder.js— the rendering engine and all UI wiring. Upload handling, CSV/TSV parsing, the five sample datasets, every style control, node dragging, circular-flow detection/rendering, PNG/JPG/SVG export, and local Save/Load (see below).sankey_builder.css— all styling.sankey.js— the Sankey layout algorithm: our own custom build (with circular-flow layout support), MIT licensed the same as everything else here — see License.d3.min.js— D3.js v7.9.0 (ISC License), bundled directly sincesankey.jsdepends on the specific version it was built against.examples/— a couple of ready-to-use sample CSVs, in addition to the five datasets already baked into the app itself.
Everything else (jQuery, Bootstrap, Bootstrap Notify, LZString, Font
Awesome) is pulled from a CDN in sankey_builder.html — swap those for
locally-vendored copies if you need this to work fully offline/air-gapped.
This is a fully static site — there's no build step and no server component
required. sankey_builder.html expects sankey_builder.css, d3.min.js,
and sankey.js under /static/css/ and /static/scripts/ respectively (a
plain Flask app's default static layout), and sankey_help.html (the Help
modal's content — see below) directly under /static/. Arrange the files
like this:
your-app/
static/
sankey_help.html
css/
sankey_builder.css
scripts/
d3.min.js
sankey.js
sankey_builder.js
sankey_builder.html (or wherever your route renders it from)
You can open sankey_builder.html straight from disk (double-click it, or
file:///... in the address bar) and everything works — diagram rendering,
uploads, styling, Save/Load — except the Help modal, which loads its
content with fetch(), and browsers block fetch() under the file://
protocol. A local server fixes that (and is what you'll want anyway once
you're testing this for real):
# from the your-app/ directory above
python3 -m http.server 8000
# then open http://localhost:8000/sankey_builder.htmlAny other static server works the same way (Flask, GitHub Pages, npx serve,
nginx, etc.) — Python's just the one that needs nothing installed beyond
Python itself.
sankey_help.html's path is deliberately absolute (/static/sankey_help.html,
set once as HELP_CONTENT_URL near the top of the Help section in
sankey_builder.js) rather than relative — that way it loads correctly no
matter what route actually serves sankey_builder.html itself. Change that
one constant if you'd rather serve it from somewhere else (a dedicated
route, a CDN, etc).
There's no backend, so "Save" is a browser file download, not an API call:
- Save (Data tab → Offline → Save) downloads a
.skdfile — LZString- compressed JSON containing your data and every style setting (colors, node positions, layout, labels, etc). - Load (Data tab → Offline → Load) re-opens a
.skdfile you saved earlier, restoring everything exactly as it was. - PNG / JPG / SVG export (Data tab → Data hub, or wherever your fork
exposes
saveDiagramAsPNG/saveDiagramAsJPG/saveDiagramAsSVG) renders the current diagram straight to a downloaded image file.
Nothing is ever sent anywhere. If you want server-backed storage, accounts, sharing links, or live data sources, that's exactly the kind of thing the hosted product at sankeybuilder.org adds — this repo intentionally doesn't try to be that.
Compared to the full product, this edition has no:
- Accounts, login, or any server calls of any kind
- Google Sheet / API-push live data linking
- Node Lock (the dedicated "freeze every position / restore to auto-layout"
buttons) — plain node dragging still works fully, and a dragged position
is still saved/restored correctly through the local
.skdfile; there's just no separate bulk lock/restore feature - Flow Intelligence (AI-generated analysis) or any AI/LLM calls
- Webhooks, API keys, or a REST API
- Billing/plans/paywalls of any kind
If you want any of that, point people at sankeybuilder.org — that's the intended relationship between this repo and the hosted product.
Everything in this repository — sankey_builder.js, sankey_builder.html,
sankey_builder.css, sankey_help.html, and sankey.js (our own custom
Sankey layout implementation, not a derivative of d3-sankey-circular or
any other third-party fork) — is MIT licensed (see
LICENSE). Do whatever you want with it: use it commercially,
modify it, white-label it, fork it, ship it inside a closed-source product.
Attribution is appreciated but not required.
d3.min.js is © Mike Bostock and the D3 contributors, ISC License —
bundled directly since sankey.js depends on the specific version it was
built against.
Issues and PRs are welcome. This is a genuinely trimmed-down extraction from a larger commercial codebase, so if you spot a leftover reference to something that no longer exists, that's a real bug — please flag it.
Need accounts, live data sources (Google Sheets / API push), webhooks, or AI-generated flow analysis on top of this? That's sankeybuilder.org.