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

fledgling

v1.3.1

Published

🐣 Hatch your new npm package safely - claim the name on npm and set up / sync trusted publishing settings, for one package or a whole monorepo.

Readme

fledgling 🐣

npm version npm downloads node license

Claim package names on npm, set up trusted publishing, and keep it all in sync β€” as config in your repo.

Brought to you by Varlock πŸ§™β€β™‚οΈπŸ” β€” check it out to keep your secrets out of plaintext.

fledgling does two things, and you can use either one on its own:

  1. Claims package names on npm β€” one command, from any directory, no repo or package.json needed. Got a name for that idea? Grab it before someone else does.
  2. Sets up token-less (OIDC trusted) publishing and keeps it in sync β€” your trusted-publishing config lives in package.json, and fledgling reconciles npm to match it. No NPM_TOKEN, no clicking through the npm website.

It works for a single package or a whole monorepo, and it's idempotent, so you can re-run it any time you add a package or change your publishing setup.

Just claim a name

Have a name you want to lock down? You don't need a repo, a package.json, or any config β€” run this from your home folder or an empty directory:

npm login                                        # once (2FA required)
npx fledgling add my-great-new-idea --new --yes  # done β€” the name is yours

That publishes a tiny 0.0.0 placeholder under your account (no code β€” just a package.json and a README saying the name is reserved), which is all npm needs to reserve the name. Scoped names (@scope/thing) work too, and you can pass several at once. When the package later lives in a repo, npx fledgling sync wires up trusted publishing β€” or never bother, and just npm publish over it like any other package.

Already in a repo and only want the names, not the trust setup? Add --skip-trust:

npx fledgling add "*" --skip-trust --yes         # claim every package in the workspace

Everything it does

Designed to be run with npx (or bunx / pnpm dlx):

npx fledgling                                # interactive walkthrough (in a terminal)
npx fledgling add my-great-new-idea --new    # claim a brand-new name, nothing in the repo yet
npx fledgling add "*" --yes                  # every package in a monorepo (globs ok)
npx fledgling sync                           # reconcile trusted publishing to your config

Run bare fledgling in a terminal and you get an interactive wizard (powered by clack); pass packages to add (or --yes / run in CI) and it goes non-interactive.

Commands

| Command | What it does | |---------|--------------| | fledgling | Interactive wizard (the default) | | fledgling add [packages…] | Claim names + set up trusted publishing for the given packages | | fledgling sync | Reconcile trusted publishing on npm with your config | | fledgling init | Write the trusted-publishing config to your package.json | | fledgling jsr [packages…] | Claim packages on JSR + link the repo for OIDC publishing |

Why

Setting up a new npm package the modern way is more fiddly than it should be:

  1. npm won't let you configure trusted publishing until the package already exists β€” so you have to publish something first.
  2. Then you configure the trusted publisher per package, by hand, on the website.
  3. In a monorepo, you do that N times.

And it doesn't end at setup. The trusted-publisher settings live on npmjs.com, not in your repo β€” so when you rename your release workflow, add a CI environment, or switch providers, every package silently falls out of sync and you're back to clicking through the website N times.

fledgling fixes both halves. It publishes a tiny placeholder to claim each name, then configures the trusted publisher for every package via npm's own npm trust β€” and it treats the fledgling block in your package.json as the source of truth, so fledgling sync reconciles what's actually on npm back to your config whenever it changes. It's idempotent β€” re-run it whenever you add a package or touch your publishing setup, and it only does what's missing or different.

Quick start

npm login        # needs 2FA enabled
npx fledgling       # interactive: pick packages, confirm, apply

Prefer non-interactive (or in CI)?

npx fledgling --dry-run    # print a plan, change nothing
npx fledgling --yes        # apply: claim names + configure trusted publishing

Then add the matching publish step to your CI (e.g. a GitHub Actions job with permissions: id-token: write running npm publish). Your real releases now publish over OIDC β€” no token required.

🐸 Next step: Bumpy handles exactly that publish step for you β€” it versions your packages, writes changelogs, and publishes over OIDC trusted publishing (no NPM_TOKEN). fledgling sets up the trust, Bumpy does the releasing β€” they pair perfectly. (This repo is released with it.)

Configuration

The recommended way to configure fledgling is a "fledgling" block in your root package.json. Set it once and every run reads it β€” CLI flags are just per-run overrides. Create it interactively:

npx fledgling init
{
  "fledgling": {
    "provider": "github",       // github | gitlab | circleci
    "workflow": "release.yml",  // the workflow whose job runs `npm publish`
    "environment": "publish",   // CI environment for the trusted publisher (optional)
    "publish": true             // allow direct `npm publish` (staged publishing is always allowed)
  }
}

CircleCI uses IDs instead of a workflow/repo:

{
  "fledgling": {
    "provider": "circleci",
    "orgId": "…",
    "projectId": "…",
    "pipelineDefinitionId": "…",
    "vcsOrigin": "github/owner/repo",
    "contextIds": ["…"],        // optional
    "publish": true
  }
}

Add "registry" to either block to target a non-default npm registry.

"permissions": "publish" | "stage" | "both" is the old form and still works (stage β†’ "publish": false, the rest β†’ true) with a deprecation note. npm grants every trusted publisher npm stage; the only real choice is direct publish.

Excluding packages

fledgling skips any package marked "private": true. To exclude public packages too β€” internal-but-published things you never want it to claim or manage trust for β€” add an "ignore" list of names or globs:

{
  "fledgling": {
    "ignore": ["@scope/internal-*", "playground"]
  }
}

Ignored packages are invisible to fledgling: they're left out of add, sync, "*" globs, and tab completion.

Extra packages (native binaries, etc.)

Some packages are published from a repo without having their own package.json in the workspace β€” the classic case is per-platform native binary packages shipped as optionalDependencies and generated at build time. Add their exact names (no globs) to an "include" list and fledgling treats them like any discovered package β€” claimed, trusted, synced, and tab-completed:

{
  "fledgling": {
    "include": [
      "@scope/my-tool-darwin-arm64",
      "@scope/my-tool-linux-x64-gnu"
    ]
  }
}

Since these have no manifest of their own, their placeholder claims carry no metadata beyond the name. They're npm-only: fledgling jsr skips them.

Defaults

| Option | Default | Notes | |--------|---------|-------| | provider | github | also gitlab, circleci | | repo | auto-detected from git origin | override with --repo | | workflow | release.yml | the workflow whose job publishes | | environment | none | Optional and unset by default β€” the trusted publisher then isn't tied to a CI environment (it works, but adds no environment gate). Setting one (e.g. publish) is recommended for security, and fledgling init pre-fills it. | | publish | true | may the trusted publisher run npm publish directly? false = staged only (npm stage, held for 2FA approval). Staging is always allowed. | | registry | your npm config | optional custom npm registry URL |

CircleCI uses orgId, projectId, pipelineDefinitionId, vcsOrigin, and optional contextIds instead of repo/workflow/environment.

Precedence is CLI flag β†’ fledgling config β†’ built-in default.

Just want to claim names?

See Just claim a name above. To skip trusted publishing entirely and only reserve package names, you can:

  • pass --new with a name that isn't in a repo (trust is skipped automatically),
  • pass --skip-trust for a single run,
  • decline the wizard's "Set up trusted publishing?" prompt, or
  • set "trust": false in your fledgling config to make it the default.

Usage

npx fledgling add [packages...] [options]

With no package arguments, add targets every public package in your workspace. Pass names or globs to narrow it down:

npx fledgling add my-pkg --yes              # one package
npx fledgling add "@scope/*" --yes          # a glob (quote it)
npx fledgling add "*-plugin" --yes          # all the plugins
npx fledgling add @scope/brand-new --new --yes   # claim a name that doesn't exist locally yet

Running bare npx fledgling (no subcommand) in a terminal drops you into the same flow interactively.

Run options

| Flag | Description | |------|-------------| | -y, --yes | Apply changes without prompting (default in a terminal is the interactive wizard) | | --dry-run | Print a plan without prompting (non-interactive) | | --new | Treat unmatched names as brand-new packages to claim (squat a name) | | --skip-publish | Only set up trusted publishing | | --skip-trust | Only claim names | | --force | Replace an existing trusted publisher (revoke + re-create) | | --placeholder-version <v> | Placeholder version (default: 0.0.0) | | --tag <tag> | dist-tag for placeholders (default: latest) | | --otp <code> | (legacy) npm 2FA one-time password, used for every npm call this run (also $NPM_CONFIG_OTP) | | --otp-secret <secret> | (legacy) TOTP secret to generate 2FA codes from as needed (also $FLEDGLING_OTP_SECRET) |

By default you don't pass either β€” npm handles 2FA itself via the browser. See 2FA.

2FA

npm requires 2FA to claim names and configure trusted publishing, and the browser flow is the normal path β€” you won't pass anything to fledgling. npm kicks you out to the web to approve with whatever your account uses (passkey, security key, or an authenticator code), then caches that approval for ~5 minutes, so a single approval covers the whole run. When prompted, tick "don't ask again for 5 minutes" so it doesn't ask once per package.

That's it for most people. fledgling stays out of the way β€” it just runs npm with the terminal attached and lets npm prompt.

npm is moving away from authenticator codes in favor of WebAuthn (passkeys and security keys), so treat this as a fallback that's on its way out β€” for a shell with no browser, or an account still on TOTP. Note that WebAuthn can't be automated headlessly at all, so if your account has moved off codes, these options simply won't apply.

  • --otp <code> β€” a single one-time password, reused for every npm call in the run.
  • NPM_CONFIG_OTP=<code> β€” same thing as an env var. It's npm's own config env var, and it keeps the code out of your process list.
  • --otp-secret <secret> β€” your authenticator's TOTP secret (base32); fledgling generates a fresh code for each npm call. Prefer the FLEDGLING_OTP_SECRET env var over the flag so the secret doesn't land in your shell history or process list.

A single code expires in ~30s, so --otp / NPM_CONFIG_OTP may not survive a long run across many packages β€” --otp-secret / FLEDGLING_OTP_SECRET mints a fresh one per call.

Pull either straight from a password manager β€” e.g. 1Password's CLI (op). The generated code comes from ?attribute=otp:

fledgling sync --otp "$(op read "op://Private/npm/Security/one-time password?attribute=otp")"

…or read the secret itself β€” the field's value with no attribute, an otpauth:// URI β€” into FLEDGLING_OTP_SECRET:

FLEDGLING_OTP_SECRET="$(op read "op://Private/npm/Security/one-time password")" fledgling sync

Config flags

Better set once in package.json (see Configuration); as flags they override the config for that run.

| Flag | Config key | Default | |------|-----------|---------| | --provider <p> | provider | github | | --publish / --no-publish | publish | --publish | | --registry <url> | registry | npm config | | --repo <owner/repo> | (auto-detected) | git origin | | --workflow <file> | workflow | release.yml | | --env <name> | environment | none | | --org-id <uuid> | orgId | (circleci) | | --project-id <uuid> | projectId | (circleci) | | --pipeline-definition-id <uuid> | pipelineDefinitionId | (circleci) | | --vcs-origin <origin> | vcsOrigin | (circleci) | | --context-id <uuid> | contextIds | (circleci, repeatable) |

What it does, precisely

For each target package:

  1. Claim β€” if the name isn't on npm yet, publish a placeholder (0.0.0, no code β€” just a package.json and a README noting the name was claimed with fledgling) to reserve it.
  2. Trust β€” if there's no trusted publisher configured, set one up for your CI provider via npm trust (or replace an existing one with --force). Supports GitHub, GitLab, and CircleCI, with every option npm trust accepts.

Both steps are skipped when already done. Placeholders are packed from a throwaway temp dir, so your real package.json files are never touched.

fledgling sync β€” reconcile trusted publishing

Where the default command focuses on new packages (and hides already-published ones), fledgling sync reconciles trusted publishing across every package against your fledgling config.

It authenticates, reads each package's actual config on npm, and shows what's not configured or out of sync β€” with the exact difference (e.g. environment publish β†’ (none)) β€” then asks before fixing it to match your config:

fledgling sync            # auth, check, then confirm + apply
fledgling sync --yes      # skip the confirm
fledgling sync "@scope/*" # a subset

Use it whenever your publishing setup changes β€” you renamed the release workflow, added a CI environment, switched providers, or tweaked permissions β€” or to set up trust on packages that were published before fledgling existed. Change the config, run sync, and every package on npm matches again. (It uses the same config/flags as the main command.)

fledgling jsr β€” the same story on JSR

JSR has no "create on first publish" β€” every package must already exist on jsr.io before anything (CI or a human) can publish a version to it. For a monorepo that's the exact papercut fledgling exists to remove, so fledgling jsr does for JSR what the main command does for npm:

  1. Scaffold β€” create a minimal jsr.json (name, version, a source exports entry) from each package.json where missing. An existing jsr.json/deno.json is authoritative and never rewritten.
  2. Claim β€” create each missing package on jsr.io via the JSR management API.
  3. Link β€” link your GitHub repo to each package, which is JSR's whole trusted-publishing setup: any workflow in the linked repo can then publish token-lessly via OIDC (npx jsr publish with permissions: id-token: write β€” no JSR_TOKEN secret in CI).
  4. Sync score metadata β€” reconcile each package's description (from package.json) and runtime compatibility (from config) to jsr.io. JSR scores packages partly on these, and β€” unlike npm β€” they live only on jsr.io (the jsr.json manifest has no description field), so they can't ride along at publish time. fledgling reconciles them here, where it already holds the token; only what's changed is pushed.
npx fledgling jsr                    # plan (interactive confirm in a terminal)
npx fledgling jsr --yes              # apply: scaffold + claim + link
npx fledgling jsr "@scope/*" --yes   # a subset

It's idempotent β€” claimed packages are skipped and the repo link is re-asserted, so re-run it whenever you add a package.

Prerequisites

  • A JSR scope you're a member of (create one at jsr.io/new) β€” fledgling doesn't create scopes.
  • A JSR personal access token with full access in $JSR_TOKEN (jsr.io β†’ Account β†’ Tokens). A token restricted to "package publish" can publish versions but cannot create packages or link a repo β€” those are management operations. The token is used once, locally; it does not go into CI.

JSR names always have a scope. Packages whose npm name already has one (@scope/pkg) map straight across; for unscoped packages, set the scope once:

{
  "fledgling": {
    "jsr": {
      "scope": "myscope",     // JSR scope for unscoped npm names (or override with --scope)
      "manifest": true,       // set false to never scaffold jsr.json
      "metadata": true,       // set false to never sync description / runtime compat
      "runtimeCompat": {      // default runtime-compatibility flags (part of the JSR score)
        "node": true, "deno": true, "bun": true, "browser": true, "workerd": true
      }
    }
  }
}

The description is taken automatically from each package's package.json (collapsed to a single line and clamped to JSR's 250-char limit). runtimeCompat is deliberately not inferred β€” set it explicitly, either as the fledgling.jsr.runtimeCompat default above or per-package in that package's own package.json (a package's own value wins). Only runtimes you mark are changed; re-running reconciles drift, so edit package.json and re-run to update jsr.io.

Flags

| Flag | Description | |------|-------------| | -y, --yes | Apply without prompting | | --dry-run | Print a plan without prompting (non-interactive) | | --scope <scope> | JSR scope for packages whose npm name has none (or to override it) | | --repo <owner/repo> | GitHub repo to link (default: auto-detected from git origin) | | --token <token> | JSR access token (prefer $JSR_TOKEN over the flag) | | --skip-manifest | Don't scaffold missing jsr.json manifests | | --skip-link | Only claim names β€” don't link the repo | | --skip-metadata | Don't sync score metadata (description / runtime compat) |

Good to know

  • Rate limits are handled. JSR's management API throttles bulk operations aggressively; fledgling backs off (honouring Retry-After) and paces itself between packages.
  • 20 new packages per scope per rolling week. JSR hard-caps new package creation, so a larger monorepo can't be bootstrapped in one run. fledgling detects the quota, stops cleanly, and lists what's left β€” re-run after the reset (or ask jsr.io for a raise); it picks up where it left off.
  • JSR's OIDC is GitHub-only today, and there's no per-workflow/environment config β€” the repo link is the whole setup.
  • JSR publishes TS source, so scaffolded manifests point at your source entry (your development/source export condition, or ./src/index.ts), not built output.

πŸ™ Thanks to @Saeris for the groundwork that made this feature possible β€” the proposal and reference implementation (including the live findings on JSR's rate limits and weekly quota) that fledgling jsr is built on.

Shell completions

fledgling ships tab-completion (via @bomb.sh/tab) that completes package names and flags. Install it for your shell:

fledgling complete zsh  >> ~/.zshrc
fledgling complete bash >> ~/.bashrc
fledgling complete fish >  ~/.config/fish/completions/fledgling.fish

Then fledgling <TAB> completes the packages in your workspace.

Requirements

  • Node β‰₯ 18
  • npm β‰₯ 11.15.0 (for npm trust + OIDC/staged publishing)
  • npm login with 2FA enabled for the trust step (npm requires it)

Supports npm / yarn / bun (workspaces) and pnpm (pnpm-workspace.yaml) monorepos, plus single-package repos.

License

MIT Β© DMNO Inc