A zero-backend, single-file Blazor WebAssembly app for exploring Gremlin, openCypher and SPARQL graphs. Connect straight from the browser, run queries, and see your data as an interactive 2D or 3D graph, a table, or raw JSON — then edit it and commit the changes back.
Blazor WebAssembly · .NET 10 · Cytoscape.js · 3d-force-graph / three.js · Monaco Editor · no server tier
Graph DB Viewer began as part of another project of mine. While exploring graph databases, I wanted a viewer that runs entirely in the browser for quick and easy testing — and couldn't find one that did. So I built my own. It stands on its own as a full tool, but it's also designed to embed directly into that project: tightly integrated, with all of its functionality available behind the scenes.
🖥️ Prefer a visual tour? See it live on the EECS blog — or open
docs/index.htmllocally (or serve thedocs/folder via GitHub Pages). A one-page presentation of everything below.
- What it is
- Highlights
- Feature tour
- Supported databases
- Running locally
- Deploying
- Embedding in another page
- How it works
- Project layout
- Testing
- Privacy & limitations
- License
Graph DB Viewer is a client-only graph tool. There is no server, no login, and no install — the whole app is static files that run in your browser and talk to your database directly. Everything you save (connections, queries, history, theme, open tabs) lives in your browser's localStorage.
It's designed for developers who want a fast, private, self-hostable alternative to heavier graph desktop tools: paste a query, get a picture, poke at the data, and move on.
| 🔌 Browser-direct connections | Talk to TinkerPop / Cosmos DB (Gremlin) over WebSocket or HTTP, and to SPARQL/RDF endpoints — no proxy in between. |
| 🎨 Four view modes | The same result as JSON, an interactive 2D graph, a 3D graph, or a sortable Table. |
| 🧭 Multiple layouts | 6 layouts in 2D (force, tree, concentric, circle, grid, random) and 6 in 3D (force + five DAG modes). |
| 🐞 gdotV-style query debugger | Step through a traversal and watch the traverser count after every step — see exactly where results vanish. |
| ✏️ Full editing | Add / edit / delete vertices, edges and properties. Changes are staged and committed explicitly. |
| 🧠 Schema-aware autocomplete | Monaco editor with real vertex labels, edge labels and property keys pulled from your live database. |
| 📥 Import | Paste GraphSON, Graphviz DOT or Mermaid and visualize it offline — or turn it into addV/addE. |
| 📤 Export | Table → CSV / colored Excel; graph → PNG / JPEG / SVG; 3D scene → OBJ / PLY / STL / glTF. |
| 🌙 Dark mode + PWA | Persisted dark theme, keyboard shortcuts, and installable/offline via a service worker. |
- Gremlin databases — Apache TinkerPop / TinkerGraph and Azure Cosmos DB (Gremlin API).
- Two transports — WebSocket (
ws(s)://host:port/gremlin, GraphSON 3op:eval) and HTTP/REST (TinkerPop REST channel, or Cosmos DBexecuteGremlinwith HMAC-SHA256 auth). - SPARQL / RDF endpoints — Fuseki, Blazegraph, GraphDB, Virtuoso, and public endpoints like Wikidata and DBpedia.
SELECT→ results table,ASK→ boolean,CONSTRUCT/DESCRIBE→ a graph. - Database-type selector on the connection form, with a CORS/reachability warning and a supported-databases table right in the UI.
- SSL toggle (
ws↔wss,http↔https), auto-derived from the port and type, with a live protocol badge and a reminder to switch SSL off for a database without a secure endpoint (and that you may need to enable CORS or put a proxy in front). - Saved connections — full add / edit / delete with duplicate-name validation, persisted to
localStorage. - Connection status indicator in the top bar, a connectivity test on connect, and a graceful close on disconnect.
- Monaco query editor (self-hosted — no npm/bundler) with syntax highlighting for Gremlin (custom Monarch grammar), openCypher and SPARQL, auto-indentation and bracket/quote auto-closing. Pick the language per tab.
- Schema-aware Gremlin autocomplete — step completion plus real vertex labels, edge labels and property keys fetched from the connected database. It's context-aware:
hasLabel('…suggests vertex labels,out('…edge labels,has('…/values('…property keys. Refreshed on connect and after every commit. - Load DB — pull the whole graph (vertices and edges, including isolated/edgeless vertices) with a configurable vertex limit.
- Saved queries — CRUD, stored locally, one click to reload.
- Query history — the last 20 executed queries, de-duplicated (re-running one moves it to the top), click to restore.
- Examples tab — curated queries grouped into Inspect, Visualize and Mutate, plus one-click sample graphs (a table-assembly tree, a social network, and flight routes) that load additively so you always have something to look at.
- ✨ Ask AI — describe what you want in plain English and a bring-your-own-key AI model (Anthropic / OpenAI / Gemini / any OpenAI-compatible server) writes the Gremlin / openCypher / SPARQL query into the editor for review — grounded in the connected schema, never auto-run. Tool-capable models can double-check themselves with read-only queries first.
- Cancellable — connect, Run Query, Load DB, Schema fetch and Commit all run under a cancellation token with a Cancel button.
Switch any result between JSON, 2D, 3D and Table instantly.
| 2D — Cytoscape.js | 3D — three.js |
|---|---|
![]() |
|
| Table | Raw JSON |
![]() |
![]() |
- 2D — Cytoscape.js — 6 layouts (Force-directed
cose, Tree/breadthfirst, Concentric, Circle, Grid, Random), directed labeled edges, and node/edge selection highlighting. - 3D — 3d-force-graph / three.js — 6 layout modes (free Force, Tree top-down, Tree bottom-up, Left→right, Radial, Z-stack), auto-coloring by vertex-label group, directional arrows, curved parallel edges and hover labels. Cyclic graphs are tolerated.
- Table view — vertices and edges as row/column tables with one column per property; click a row to select the element. Vertex rows are tinted with their label's configured color.
- Search & filter — find nodes by label / id / property value (2D highlights + fits, 3D centers), plus a type-label filter to show/hide vertices by label, in both graph views.
- Styling — per label or per node — color, size, display-property, icon URL and a new 3D-model URL (an
.obj/.zipthat replaces the node's sphere in 3D), set either per vertex label (saved in the browser) or per node (saved to the database asgdbv*properties that override the label style and commit like any edit — the per-node scope can also pin the node's X/Y/Z position). Color/size apply live. - Double-click to expand — grow the graph outward from a node by loading its neighbors.
- Center / fit control and live layout switching with no graph rebuild.
- Graph stats — a
N vertices · M edgesline under each graph, plus the last query's execution time (… · 12 ms query). - Multiple query tabs — each tab is an independent workspace (its own query, results, view mode, layout, search/filter, styling and selection). All open tabs are persisted and restored on reload; double-click a tab to rename it.
A gdotV-style step-through debugger for Gremlin:
- Runs the query truncated at each step (prefix re-execution) and shows the traverser count after every step, with zero-drops highlighted so you can see exactly where results disappear.
- Steps are underlined and clickable in the editor — click one to sample it or visualize that intermediate result in 2D/3D. The editor goes read-only during a debug session.
- A Profile tab (parsed
profile()metrics — count / traversers / time / %) and an Explain tab. - Mutation-safe:
addV/addE/drop/property/mergequeries are refused, so debugging never changes your graph.
- Select a node or edge (click it in the graph, or click a table row) to open the property editor.
- Add / edit / remove vertex and edge properties.
- Add / remove edges on the selected node, choosing direction (in / out).
- Two-click edge creation — activate, click source then target, give it a label.
- Create a new vertex by label; delete an element via button, the Delete key, or a delete mode (trash-icon toggle) where clicking any node or edge stages a drop for it — deleting a vertex also drops its incident edges so none are left dangling.
- Every mutation is staged into a Generated queries buffer and committed explicitly — with per-line error reporting and optional auto-reload after commit — so nothing changes until you say so.
- Preview uncommitted edits — a Preview data changes switch below the 2D/3D canvas: turn it on to see staged adds, removes and style/position changes on the canvas immediately (with an on-canvas warning) before you commit.
Import / paste
- Paste GraphSON (from the app's own Copy graph), Graphviz DOT, or Mermaid flowcharts and visualize them offline — no connection needed.
- DOT / Mermaid also generate
addV/addEinto the query editor, ready to import into a real database. - ✨ Generate with AI — paste text, load a file (
.docx,.xlsx,.csv,.txt/.mdor any text-based format), or fetch a Wikipedia article, and an AI model extracts a knowledge graph from it: strict-JSON output, validated and entity-de-duplicated client-side, previewed with counts and warnings, then staged asaddV/addE— merging into or replacing the current drawing, your choice, with nothing committed until you say so. - Cloud file picker (currently hidden) — the Dropbox / OneDrive / Google Drive file-picker button is temporarily disabled; the provider interop still ships in the codebase.
Export
- Table → CSV or a color-styled Excel
.xlsx(hand-rolled OpenXML, no dependency — vertex rows filled with their label color). - Image → PNG, JPEG, or SVG (SVG for the 2D view).
- 3D scene → OBJ, PLY, STL or glTF.
- Dark mode, persisted, with tuned contrast.
- Keyboard shortcut: Delete removes the selected element.
- Installable PWA with a service worker for offline use.
- Full-width toggle in the top bar — drop the page's side margins to fill the viewport; the margins are sized in
vwso they hold steady when you zoom, and the choice is remembered per browser. - About modal (with links to the blog post and the GitHub repo) and a resizable two-pane layout (results/graph on the left, editor + property panel on the right) — drag the divider to change the split, or double-click it to reset to the default ratio.
| Database | Protocol | Status |
|---|---|---|
| Apache TinkerPop / TinkerGraph | Gremlin over WebSocket or HTTP | ✅ Supported |
| Azure Cosmos DB (Gremlin API) | Gremlin over WebSocket/HTTP + HMAC-SHA256 | ✅ Supported |
| Apache Jena Fuseki, Blazegraph, GraphDB, Virtuoso | SPARQL 1.1 over HTTP | ✅ Supported |
| Public SPARQL (Wikidata, DBpedia) | SPARQL over HTTPS | ✅ Supported |
| Neo4j / Memgraph, ArangoDB, Dgraph, Neptune, … | — | 🔭 On the roadmap |
Because connections are made directly from the browser, the target endpoint must be reachable from your machine and must either allow CORS (HTTP/SPARQL) or accept a WebSocket from your origin. The app shows a reachability warning to remind you.
Prerequisites:
- the .NET 10 SDK — all you need to run the app
- Node.js 20+ — only for the JS unit tests and the Playwright e2e tests (see Testing)
- Docker — only if you want a local Gremlin database to play with (optional, below)
Clone and run:
git clone https://github.com/EECSB/GraphDBViewerWeb.git
cd GraphDBViewerWeb
dotnet run --project GraphDBViewerWebWindows note: clone into a reasonably short path (e.g.
C:\src) or rungit config --global core.longpaths truefirst — the repo contains deeply nested files that can exceed the default 260-character path limit.
Then open the URL it prints (dev server is configured for http://localhost:5154). No database is required to try it — open the Examples tab and load one of the sample graphs, or paste a Mermaid/DOT snippet into the Visualize pasted graph box.
To point it at your own database, expand the connection card in the top bar, pick the database type, fill in host/port (and auth for Cosmos DB / SPARQL), and hit Connect.
docker run -d -p 8182:8182 tinkerpop/gremlin-serverThat serves an in-memory TinkerGraph at ws://localhost:8182/gremlin — no SSL, and the data is lost when the container restarts. Seed it with a small product-composition sample by editing $endpoint at the top of gremlin-load-sample.ps1 to your server and running the script with PowerShell 7. Then connect in the app with: type Apache TinkerPop, transport WebSocket, SSL off, host localhost, port 8182.
No Docker handy? Pick the SPARQL / RDF database type and the public Wikidata endpoint https://query.wikidata.org/sparql — zero setup — and try SELECT * WHERE { ?s ?p ?o } LIMIT 10.
It's a static Blazor WebAssembly app, so it deploys anywhere that serves static files — GitHub Pages, Azure Static Web Apps, Netlify, S3, Nginx, etc.
cd GraphDBViewerWeb
dotnet publish -c Release
# output: bin/Release/net10.0/publish/wwwrootServe the contents of publish/wwwroot. To host the presentation page on GitHub Pages, point Pages at the repo's docs/ folder — docs/index.html is self-contained.
Drop the viewer into any web page with an <iframe>. Pass settings in the URL's query string and it comes up pre-configured — connected, with a query already run, in the view you want:
<iframe
src="https://your-host/?dbType=tinkerpop&host=192.168.1.5&port=8182&ssl=false&query=g.V().limit(25)&view=2d"
width="100%" height="720" style="border: 0;">
</iframe>A SPARQL example (endpoint-only is inferred as SPARQL):
<iframe
src="https://your-host/?endpoint=https://query.wikidata.org/sparql&view=table&query=SELECT%20%2A%20WHERE%20%7B%20%3Fs%20%3Fp%20%3Fo%20%7D%20LIMIT%2010"
width="100%" height="720" style="border: 0;">
</iframe>Tip: URL-encode the
queryvalue (e.g.encodeURIComponent(...)), especially when it contains spaces, quotes or&.
Supported query-string parameters (all optional, case-insensitive):
| Group | Parameter | Values / notes |
|---|---|---|
| Connection | dbType |
tinkerpop · cosmos · sparql (endpoint-only is inferred as SPARQL) |
transport |
ws (WebSocket) · http |
|
host, port |
Gremlin host and port. A non-TLS port (e.g. 8182) implies ssl=false. |
|
ssl |
true / false — defaults from the port when omitted |
|
database, collection |
Azure Cosmos DB only | |
authKey |
Cosmos key / password, or SPARQL basic-auth password | |
endpoint |
SPARQL endpoint URL | |
username |
SPARQL basic-auth username | |
| Query | query (or q) |
Initial query text |
lang |
gremlin · cypher · sparql (editor highlighting) |
|
run |
true (default) / false — auto-run the query once connected |
|
| View | view |
json · 2d · 3d · table |
| Control | connect |
true (default) / false — auto-connect using the details above |
The viewer connects directly from the browser, so the same reachability/CORS rules apply to the embedded frame. Because authKey would appear in the URL, avoid putting production credentials in an embed on a shared or public page.
- Blazor WebAssembly, client-only — there is no server tier and no
Gremlin.Netdependency; it usesSystem.Net.Http+System.Text.Jsonso it runs in WASM. - Transports: raw WebSocket with GraphSON 3 framing, and HTTP REST (with Cosmos DB HMAC-SHA256 auth).
- Persistence:
Blazored.LocalStoragefor connections, saved queries, history, last query, open tabs and theme. - Rendering: Cytoscape.js (2D) and 3d-force-graph / three.js (3D), driven through thin JS interop layers. The Monaco editor is vendored under
wwwroot/lib/monaco(no CDN, no bundler).
Key source files:
| File | Responsibility |
|---|---|
Code/Db/GraphDb.cs / Code/Db/GraphDbProviders.cs |
The database seam: IGraphDb + the normalized GraphDbResult, and the per-database capabilities the UI gates on. |
Code/Gremlin/GremlinDB.cs |
An IGraphDb: connection + query execution over WS/HTTP; GremlinConnection. |
Code/Sparql/SparqlDb.cs / Code/Sparql/SparqlConverter.cs |
An IGraphDb: SPARQL HTTP query + results → table/graph. |
Code/Graph/GraphDataConverter.cs |
GraphSON → Cytoscape (2D) / 3d-force-graph (3D) / Table models. |
Code/Gremlin/GremlinQueries.cs |
Pure Gremlin query-string builder, traversal step-parser (for the debugger) and curated example queries. |
Code/Graph/GraphImport.cs |
DOT / Mermaid → node/edge model → render JSON + addV/addE. |
Code/Utils/ExcelExport.cs |
Hand-rolled colored .xlsx export. |
Code/Gremlin/SchemaBuilder.cs |
Builds the schema used for autocomplete. |
Pages/Home/Home.razor |
The single-page UI. |
wwwroot/js/*Interop.js |
Cytoscape, 3D force-graph, Monaco, export, keyboard, URL-availability and cloud-picker interop. |
GraphDBViewerWeb/ # the Blazor WebAssembly app
Code/ # C# core, grouped into Gremlin/ · Sparql/ · Graph/ · Utils/
Components/ # Razor UI components (TopBar, TableView, MonacoEditor, …)
Pages/Home/Home.razor(.cs) # main page
wwwroot/ # index.html, JS interop, vendored libs (Cytoscape, three, Monaco)
GraphDBViewerWeb.Tests/ # xUnit tests for the pure C# logic + bUnit markup tests
docs/index.html # this project's presentation / landing page
README.md
The pure C# logic (query builder, GraphSON conversion, DOT/Mermaid import, SPARQL conversion, Excel export, step parsing, expansion, cancellation) is covered by xUnit tests, and the Razor markup layer — the option values and form shapes the C# reads back — by bUnit component tests in the same project:
dotnet testThe pure JS geometry helpers run under the built-in Node test runner:
npm testThe DOM / three.js / Cytoscape-bound rendering layer is covered by Playwright e2e tests in e2e/. The Playwright config starts the app itself (dotnet run on port 5000), and the specs load their fixture graph offline through the DOT import — no database needed:
npm install # once — pulls @playwright/test
npx playwright install chromium # once — the test browser
npm run test:e2eThe double-click-expansion spec is the one test that needs a live, seeded Gremlin server; it is skipped unless GREMLIN_E2E_HOST (and optionally GREMLIN_E2E_PORT) points at one (seed the dev server with gremlin-load-sample.ps1).
- Everything stays local. Queries go straight from your browser to your database; connection details and history are stored only in your browser's
localStorage. - Auth keys are stored in
localStoragein plain text — appropriate for a single-user local/developer tool, but don't use it on a shared machine with production credentials. - Some databases require a backend proxy to reach from a browser (e.g. Amazon Neptune's VPC + SigV4). Those are out of scope for this client-only tool.
Graph DB Viewer is dual-licensed:
- Noncommercial use is free under the PolyForm Noncommercial License 1.0.0 — personal and hobby projects, research, education, and nonprofits.
- Commercial use requires a paid license — see COMMERCIAL-LICENSE.md.
Bundled third-party libraries keep their own permissive (MIT) licenses — see THIRD_PARTY_NOTICES.md.





