Skip to content

Registry: getting started

Build a registry of your own, serve it as static JSON, and install from it with the same CLI.

Requirements

A registry is files on a static host. Anything that can serve JSON over HTTPS with CORS will do: a CDN, an S3 bucket, GitHub Pages, or the public/ directory of the app you already deploy.

Write the items

Keep your components where you develop them and generate the registry from there — that way the source you edit and the source you publish cannot drift. The builder in this repository, apps/www/scripts/build-registry.mts, is small enough to copy: it reads a list of items, inlines each file’s contents, and writes public/r/index.json plus public/r/styles/default/<name>.json.

import { promises as fs } from "node:fs"
import path from "node:path"

const OUT = path.join(process.cwd(), "public/r")

for (const item of items) {
  const files = await Promise.all(
    item.files.map(async (file) => ({
      ...file,
      content: await fs.readFile(file.path, "utf8"),
    }))
  )
  await fs.writeFile(
    path.join(OUT, "styles/default", `${item.name}.json`),
    JSON.stringify({ ...item, files }, null, 2)
  )
}

Serve it

Deploy the directory. If it lands at https://acme.dev/r, then https://acme.dev/r/index.json and https://acme.dev/r/styles/default/button.json both have to answer.

Install from it

Point one command at it:

npx newtui@latest add button --registry https://acme.dev/r

Or set it once, for every command in the project:

{
  "registry": "https://acme.dev/r"
}

NEWT_REGISTRY_URL does the same thing for a shell session, which is the convenient form in CI.

A full URL also works in place of a name, which is the quickest way to test a single item before you publish an index:

npx newtui@latest add https://acme.dev/r/styles/default/button.json

Depend on newt/ui

An item’s registryDependencies may name items in your own registry. To build on top of newt/ui rather than beside it, vendor the components you extend into your registry with newtui add, then list them as dependencies of your own items — that keeps a single resolution pass and one copy of each file in the consumer’s project.