Docs & Code Guide

Embed a diagram in an npm README: absolute URLs, and the picture that updates without a release

By the engineer who builds Datadef, from client work on data platforms · Reviewed August 21, 2026

The most common npm README bug is an image that renders on GitHub and shows a broken icon on npmjs.com. The cause is structural rather than a typo: npm renders the README out of the published tarball, with no repository context to resolve a relative path against. The fix is an absolute URL, and once you are using one anyway, it is worth choosing an address that can still change after the release goes out.

6 min readFor maintainers of published npm packages

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

145/20003 credits left
Try:

No account needed · Editable canvas, not a picture

Why the image works on GitHub and not on npm

On GitHub, a relative path like ./docs/architecture.png resolves against the repository at the branch you are viewing, so it just works. On npmjs.com the README arrives inside the tarball, detached from the repository, and the rewriting npm attempts points at the default branch named in the repository field. It misses often enough to have earned its own long-lived bug report: npm/marky-markdown issue 432, Relative links in markdown README not being rewritten on npmjs.org. Maintainers have been filing the same broken-image complaint against the registry ever since.

The failure is silent for the author, because the file being previewed locally and on GitHub is fine. It shows up only on the package page, which is the page most consumers actually read before installing.

Use an absolute https address for every image in a published README. That single rule removes the whole category, whether the target is a raw file in the repository or a rendered diagram endpoint.

<!-- Breaks on npmjs.com -->
![Architecture](./docs/architecture.png)

<!-- Works, and stays current between releases -->
![Architecture](https://datadef.io/api/embed/my-package-a1b2c3d4?width=1600&height=900)

The npm page is a photograph of your publish

The README shown on a package page comes from the version that was published. Editing README.md on the default branch changes the GitHub view immediately and the npm page not at all, until the next release. Package pages for older versions keep the README they shipped with.

That has an underappreciated consequence. Between releases, an image address is the only element of the npm page whose content you can still change. The words are frozen, the picture does not have to be. A diagram behind a live URL means the package page shows the current architecture even when the last release was in March.

It also means a broken image line is a mistake you cannot correct without cutting a version, which is a good reason to open the package page after every publish and look at it once.

What npm renders and what it removes

npm renders the README as GitHub Flavored Markdown and sanitizes the result. Scripts, styles and iframes do not survive, so there is no interactive embed on a package page. Images and a conservative subset of HTML do survive, which is why the image-by-URL route is the only live option here.

Keep the markup ordinary. Fancy theme-switching markup that works on GitHub is not worth relying on inside a sanitized renderer you do not control; a single image line behaves identically everywhere the README is read, including the npm CLI page, the package page, and any mirror rendering the same tarball.

Sizing for a narrow column

The README column on a package page is narrow, and a diagram rendered for a wide screen arrives scaled down. The embed endpoint takes width from 600 to 4000, height from 400 to 4000, scale from 1 to 3, and format png or jpeg, with a default of 1600 by 1000 at 2x. For a package page, a 16 by 9 or wider render with a modest node count reads better than a tall one.

Format choice is mundane: PNG for a diagram with flat fills and text, which is nearly always the right answer, JPEG only when the render carries a photographic background. Both come from the same endpoint through the format parameter.

If the package documents a library rather than a service, the diagram worth putting here is usually the runtime picture: what the package talks to when it runs, not the file tree. Consumers are deciding whether it fits their system.

Private packages, public diagram

The embed address resolves only while the project is shared publicly. A private scoped package can still carry one, since the README is only visible to people with access, but the diagram itself is public to anyone who has the URL. Keep internal hostnames and account identifiers out of it. See sharing documentation.

Keeping the picture true across releases

Connect the repository read-only from GitHub, GitLab or Azure DevOps and the daily sync regenerates the diagram and an architecture.md from the source. For a package repository that means the diagram tracks refactors without anyone remembering to redraw it before a release.

Regenerating is not starting over. Once a diagram exists, every later run is handed the previous version's node ids, labels and zone names with an instruction to reuse each one that still applies, so a release that adds a dependency adds a node rather than returning a differently shaped picture with different names. That restraint matters more on a package page than almost anywhere else: the markdown around the image is frozen at publish, so the picture has to stay recognisable to somebody who last looked at it three versions ago.

The same live address works in the repository README, so the GitHub page and the npm page show one picture rather than two that disagree. The GitHub side has its own wrinkles, mainly the image proxy, covered in embed an architecture diagram in a GitHub README.

FAQ

Why are images in my README not showing on npmjs.com?

Almost always a relative path. npm renders the README from the published tarball without the repository context that makes ./docs/image.png resolve on GitHub, and the rewriting it attempts is unreliable. Replace relative paths with absolute https addresses and republish. The registry has carried an open bug report about exactly this for years, so the behaviour will not change under you, and the same rule fixes badges and screenshots rather than only diagrams.

Does updating the README on GitHub update the npm package page?

No. The npm page shows the README from the published version, so changes to the default branch appear only after the next publish. Older version pages keep the README they were published with. That is worth remembering before a release, because the package page is the first thing most people read and a mistake in it cannot be corrected without cutting a new version. Open the page once after every publish.

Can anything on an npm package page change between releases?

Only the content behind an address. The markdown is frozen at publish, but an image served from a URL renders whatever that URL returns today, which is how a diagram on a package page can stay current without a version bump.

Can I embed an interactive diagram on an npm package page?

No. npm sanitizes the rendered README and removes iframes and scripts, so only an image can appear. Add a plain link next to the image for readers who want the interactive view with pan and zoom. The image itself can still be live, because npm renders whatever the address returns at read time rather than a copy stored at publish.

What size should the README diagram be?

The default 1600 by 1000 at 2x scale renders sharply and scales down cleanly in the narrow package-page column. The endpoint accepts a width from 600 to 4000, a height from 400 to 4000, and a scale from 1 to 3, in PNG or JPEG.