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

@datnguye/erd-flow

v1.0.1

Published

An entity-relationship diagram component for dbt projects — table nodes, self-drawing foreign-key edges, and pluggable layouts.

Readme

@datnguye/erd-flow

CI Release npm version npm downloads License: MIT GitHub stars

A React Flow entity-relationship diagram for dbt projects: table nodes with per-column PK/FK badges, self-drawing foreign-key edges that land on the exact joined rows, and pluggable layouts (hierarchical, radial, force). It renders the dbterd json-target shape directly, so a host just hands it data and a couple of callbacks — the graph owns no transport and no theme of its own.

It powers the ERD in both dbt-docs (a static docs SPA) and dbterd-vscode (a VS Code webview). Turns out one diagram is enough for two very different homes.

Demo

The erd-flow demo: table cards with PK/FK badges and self-drawing foreign-key edges landing on the joined rows, in the hierarchical layout

The repo ships a Vite playground wired to a sample dbt-style payload — the fastest way to see the diagram move before writing a line of host code:

git clone https://github.com/datnguye/erd-flow
cd erd-flow
npm install
npm run dev

Open the printed URL at /demo/index.html. The toolbar switches layout (hierarchical / radial / force), focuses a table's FK neighbourhood, toggles column collapsing, and locks the canvas. The same knobs work as URL params for sharable states: ?layout=hierarchical, ?focus=<node-id>, ?collapse=off, ?locked=on.

Install

npm install @datnguye/erd-flow

React, React DOM, @xyflow/react, and @dagrejs/dagre are peer dependencies — the package externalizes them so your app owns their versions.

Usage

import { ErdFlow } from "@datnguye/erd-flow";
import "@datnguye/erd-flow/styles.css";

export function Diagram({ payload }) {
  return (
    <div style={{ width: "100%", height: "100vh" }}>
      <ErdFlow
        data={payload}
        layout="radial"
        onOpenNode={(node) => open(node.model_path)}
        onNodeActivate={(node) => setDetails(node)}
        labelFor={(node) => node.name}
      />
    </div>
  );
}

ErdFlow fills its parent, so give the parent an explicit size.

Props

| Prop | Type | Notes | |---|---|---| | data | ErdPayload | The nodes/edges to render (dbterd-native shape). | | layout / defaultLayout | string | Controlled or initial layout — a built-in ("hierarchical" \| "radial" \| "force") or a name added via registerLayout. Unknown names fall back to the default. | | estimateSize | (node, visibleColumns, hasToggle) => { width, height } | Override the layout-box estimate when your CSS changes the card geometry. | | filter | string | Highlights matching tables, dims the rest — never removes them. | | hideUnconnected | boolean | Drops zero-edge island tables. | | focus / focusDepth | string / number | Render only a node's FK neighbourhood. | | compact | boolean | Show only key (PK/FK) columns per table. | | collapseColumns | boolean | Collapse wide tables to a few rows with a "N more" toggle (default true). false shows every column — for a focused view where join columns must stay visible. | | expandAll | boolean | Controlled expand-all: forces every collapsible table open (true) or closed (false). Omit to let per-table toggles work independently. | | onExpandStateChange | ({ allExpanded, canExpand }) => void | Reports the aggregate expand state so a host can label/disable its own expand-all button. | | interactive | boolean | Pan / zoom / drag (default true). false locks the canvas and releases the wheel so the page scrolls past it — gate it behind a "click to unlock" affordance. | | onNodeActivate | (node \| null) => void | Header click activates; pane click clears. Render your own details pane. | | onOpenNode | (node) => void | Table double-click — open the backing model. | | resourceMeta | Record<string, ResourceMeta> | Colour/icon per resource_type. Merged over dbt defaults. | | labelFor | (node) => string | Display label; defaults to node.name. | | theme | ErdTheme | CSS-var overrides (see below). | | colorMode | "light" \| "dark" \| "system" | React Flow colour mode (default "dark"). | | minimap / controls / background | boolean | Toggle the built-in chrome. | | showSchema | boolean | Render schema_name right-aligned in each table header (default false). | | compositeEdges | "bundle" \| "fan" | Multi-column FK rendering: one bundled edge with per-column tails (default), or one independent edge per column pair. | | edgePath | "cubic" \| "smoothstep" | Path shape for single-column edges (default "cubic"). | | animateEdge | (edge) => boolean | Gate the marching-ants dash per edge; default animates every FK edge. | | dimOnSelect | boolean | While an edge is selected, fade every other edge and non-endpoint node (default false). | | onlyRenderVisibleElements | boolean | Mount only in-viewport nodes/edges — for very large uncapped ERDs (default false). | | fitViewOptions | FitViewOptions | Padding / zoom clamps applied to the initial fit and every re-fit. | | refitKey | unknown | Change it to request a re-fit (e.g. pass your fullscreen state). | | className | string | Extra class name appended to the root element. |

Custom layouts

Layouts are a name → engine registry. Register your own and select it by name — the engine receives pre-sized nodes (see estimateSize) and only decides placement:

import { registerLayout, type LayoutEngine } from "@datnguye/erd-flow";

const snowflake: LayoutEngine = (sized, edges, { centerId }) => {
  // return [{ id, x, y, dimensions: { width, height } }, ...]
};
registerLayout("snowflake", snowflake);

<ErdFlow data={data} layout="snowflake" />

Theming

Every colour is a CSS custom property with a built-in fallback, so the default is a usable dark ERD. Map your own tokens either via the theme prop or by setting the --erd-* variables in CSS:

.my-erd {
  --erd-node-bg: var(--vscode-editor-background);
  --erd-border: var(--vscode-focusBorder);
  --erd-accent: var(--vscode-charts-yellow);
}

Tokens: --erd-node-bg, --erd-node-fg, --erd-border, --erd-accent, --erd-fk, --erd-header-bg, --erd-hover-bg, --erd-muted-fg, --erd-link-fg, --erd-divider, --erd-icon, --erd-font-mono, --erd-edge, --erd-edge-selected, --erd-edge-width, --erd-edge-selected-width, --erd-minimap-bg, --erd-minimap-dim, --erd-minimap-mask, --erd-shadow.

Data shape

The payload uses dbterd's native json-target field names — an edge's from_id is the FK/child side, to_id the referenced/parent side:

interface ErdPayload {
  nodes: ErdNode[];   // { id, name, resource_type?, schema_name?, columns, ... }
  edges: ErdEdge[];   // { id, from_id, to_id, from_columns?, to_columns?, ... }
  metadata?: ErdMetadata;
}

toFlowGraph, windowPayload, erdNeighborhood, and compactColumns are exported for hosts that want to pre-process the payload themselves.

Development

npm install
npm run build       # tsc -b && vite build → dist/ (ESM + .d.ts + css)
npm test            # vitest
npm run typecheck

License

MIT © Dat Nguyen