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

@jhzlo/resin

v0.2.8

Published

A small language for entity-relationship diagrams, drawn as SVG.

Readme

resin

CI License: MIT

A small language for entity-relationship diagrams.

resin describes a database schema the way you read DDL: columns, keys, nullability, physical and logical references, indexes, encrypted columns, audit tables. It checks what you wrote and draws it as an SVG where every foreign key row is wired to the primary key it points at.

Try it in the playground | Docs | Language reference | Contributing

Paste DDL from DataGrip or another database tool. Focus on connected entities and trace key references. Save named documents locally, review import notes, add logical relations, compare DDL versions, and export a diagram or an editable .erd file.

Preview: type a reference in the editor and resin draws it from the column. Click to watch the full resin demo.

Watch the 16-second demo | Download MP4 (7.1 MB)

service accounts "Accounts service" {
  external table users "People who sign in" {
    id  bigint  pk
  }
}

table orders "Customer orders" {
  id          bigint       pk
  user_id     bigint       ~> users  "Customer"  index as idx_user_id
  order_no    varchar(32)  uk as uk_order_no  "Order number"
  buyer_name  varchar?     enc  "Buyer name"
  status      varchar      enum(PENDING, PAID, CANCELED)  index as idx_status
  created_at  datetime
  updated_at  datetime
} audit envers(user_id, status)

table order_items "Order lines" {
  id          bigint  pk
  order_id    bigint  -> orders.id
  product_id  bigint
  quantity    int
  unique(order_id, product_id) as uk_order_product
}

Why

A schema carries facts that its diagram usually loses: which columns may be empty, whether a reference is a real FOREIGN KEY or one only the application keeps, which column points where, which columns are indexed, unique or encrypted. They end up in notes and comment strings, written by convention and checked by nobody.

resin makes them syntax. Because the facts are structured, they can be checked (a reference to a missing table is an error, not a typo in a note), and they can be drawn precisely.

What it does

varchar? is nullable. -> is a physical foreign key and ~> a logical one. uk, index, enum(...), enc and composite unique(...) are modifiers, not comments.

References are checked. Missing tables and columns, nullable primary keys, duplicate names and type mismatches come back with a line, a column and a hint on how to fix them. external table declares a table owned by another service, so references to it are checked too, and the diagram shows where the boundary is. audit envers(...) generates the Hibernate Envers *_aud and revinfo tables.

resin draws the SVG itself, with each connector running from a foreign key row to the primary key row it points at. Its default look is plain ink that reads on light and dark pages; the glass looks set the tables on frosted glass over a background of their own, in three themes (aurora, silk and caustic), each dark or light. The same input always gives byte-identical output, and the renderer has no runtime dependencies: it takes an ELK instance that you pass in.

For a schema split across services, npx resin schema.erd --services draws each service as one card that lists its tables, with references inside a service counted and the ones between services running from table to table, so the dependencies between services are the picture.

Lint rules go further than compiling: they point at a reference column without an index, a table without a primary key or one nothing joins, a column name typed two ways, and an index another one covers. npx resin schema.erd --lint fails a CI step on any of them.

resin has one layout, with columns lined up within each table. npx resin fmt schema.erd rewrites a file in it, keeping every comment, and --check fails a CI step on a file that is not formatted. The playground formats with Shift + Alt + F.

Schema changes can be reviewed as pictures. npx resin diff old.erd new.erd draws the newer version with added, removed and changed tables and columns marked, and as a GitHub Action (uses: JHZLO/resin@main) resin keeps a comment with that drawing on every pull request that changes a .erd file.

The other way works too: npx resin schema.erd --to-sql postgres writes the DDL for MySQL, PostgreSQL, SQLite, SQL Server or Oracle, a schema per service, or one service's own database with --service. Importing that DDL gives the same document back.

An existing schema does not have to be written by hand. Paste a CREATE TABLE script into the playground, or run npx resin schema.sql --from-sql, and it comes back as resin: keys, indexes, foreign keys, enum values and comments carry over, from MySQL, PostgreSQL, SQLite, SQL Server or Oracle DDL, dumps included. What resin cannot write yet stays as a comment in its table.

In the playground the glass is live: the background drifts, the stars twinkle and the glass catches the light under your pointer. Click a table name to see its columns, indexes and relations as tables, or a column to see its details. Click a service's name to see what it owns, what it depends on and what uses it. Connectors can be angular or curved.

Getting started

Install resin from npm in the project that keeps your schemas, with elkjs for drawing. It needs Node 22.18 or newer.

npm install --save-dev @jhzlo/resin elkjs

Draw a file as SVG:

npx resin schema.erd > schema.svg
npx resin schema.erd --look aurora-dark > schema.aurora-dark.svg
npx resin schema.erd --keys --curved > schema.keys.svg

Convert SQL DDL to resin:

npx resin schema.sql --from-sql > schema.erd

Errors come out in compiler format:

schema.erd:3:26: error: referenced table `user` is not in this document
  |
3 |   user_id     bigint  ~> user
  |                          ^^^^
  = hint: declare it with `external table` if it lives outside this document

Using the library

npm install @jhzlo/resin elkjs
import ELK from "elkjs";
import { compile, formatDiagnostic, toSvg } from "@jhzlo/resin";

const result = compile(source);
for (const d of result.diagnostics) console.error(formatDiagnostic(d, source, "schema.erd"));

if (result.model) {
  const { svg } = await toSvg(result.model, new ELK(), { standalone: true });
}

compile returns the syntax tree, the diagnostics, and, when there are no errors, the resolved model. toSvg draws a model; options choose the look (graphite, the default, or a glass theme such as aurora-dark), all columns or key columns only, and folded or expanded audit tables. fromSchema writes a schema held as data, such as what a live database reports, as resin. @jhzlo/resin/viewer is the playground's canvas and table panel for a page of your own; see Embedding the viewer.

The language at a glance

| You write | It means | |---|---| | name varchar(32)? | A nullable column. Without ? it is NOT NULL | | pk, uk, uk as uk_name | Primary key, single-column unique (optionally named) | | -> table.column, ~> table | Physical foreign key; logical reference (defaults to the primary key) | | index, index as ix_name | An index starting at this column | | enum(A, B), enc | Allowed values; stored encrypted | | unique(a, b) as uk_ab, index(a, b) | Composite constraints | | external table t { ... } | A table owned elsewhere that you can reference | | service s "Order service" { tables } | The tables one service owns, drawn as an area; a -> into another service is a warning | | } audit envers(a, b) | Hibernate Envers audit tables for the listed columns | | `order-items` | A name with characters outside [A-Za-z0-9_] |

The docs walk through each construct with a diagram for every example. The full grammar and the rules for cardinality are in the language reference.

Status

resin is young and pre-1.0. The grammar may still change between minor versions; when it does, the parser recognizes the old form and tells you how to write it now. See the changelog.

Contributing

Issues and pull requests are welcome. CONTRIBUTING.md explains how the project is laid out and how a grammar change goes from the spec to the implementation.

License

MIT