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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@glacion/bunner

v0.3.6

Published

`bunner` is a tiny, Bun-native task runner. Define your build, test, or release flow as a dependency graph of `Node`s and `Command`s, then run any portion of that graph with one command. Tasks stream their colored output as they execute, run concurrently

Readme

bunner

bunner is a tiny, Bun-native task runner. Define your build, test, or release flow as a dependency graph of Nodes and Commands, then run any portion of that graph with one command. Tasks stream their colored output as they execute, run concurrently when possible, and can be visualized as Graphviz DOT for quick sanity checks.

Requirements

  • Bun 1.1+ (the CLI uses #!/usr/bin/env bun and Bun's spawn API)
  • macOS, Linux, or WSL2 (Graphviz is optional, only needed when rendering .dot)

Installation

Install bunner alongside your Bun project (either locally or globally):

# project-local (recommended)
bun add -d @glacion/bunner

# or make the CLI globally available
bun add -g @glacion/bunner

After installing, bunx bunner (or the globally installed bunner) becomes available.

Quick start

Create a bunner.ts file at the root of your repo and export a single Node. This file is the default task definition file, and the CLI entrypoint is index.ts. Each child node becomes addressable via its fully-qualified name (<parent>:<child>).

// bunner.ts
import { Command } from "./lib/command";
import { Node } from "./lib/node";

const root = new Node({ name: "bunner" });

const install = root.child(new Command({ name: "install", command: ["bun", "install"] }));
const lint = root.child(new Command({ name: "lint", command: ["biome", "ci"], dependencies: [install] }));
const test = root.child(new Command({ name: "test", command: ["bun", "test"], dependencies: [install] }));

root.child(
  new Command({
    name: "publish",
    command: ["bun", "publish"],
    dependencies: [lint, test],
  }),
);

export default root;

With that definition in place you can:

# List all known tasks
bunx bunner

# Run every task whose name matches the regex "lint|test"
bunx bunner "lint|test"

# Run the publish pipeline (dependencies run first, concurrently when possible)
bunx bunner publish

Examples

Workspace build + deploy

The snippet below shows how you can fan out builds per package while keeping the CLI invocations short.

// bunner.ts
import path from "node:path";
import { Command } from "./lib/command";
import { Node } from "./lib/node";

const root = new Node({ name: "bunner" });
const workspace = root.child(new Node({ name: "workspace" }));

const apps = ["web", "docs", "landing"];
apps.forEach((app) => {
  workspace.child(
    new Command({
      name: app,
      cwd: path.join(import.meta.dir, "apps", app),
      command: ["bun", "run", "build"],
    }),
  );
});

root.child(
  new Command({
    name: "deploy",
    command: ["bun", "run", "scripts/deploy.ts"],
    environment: { AWS_PROFILE: "prod" },
    dependencies: [/workspace:/], // wait for every workspace:<app> build
  }),
);

export default root;

Run a single build or the whole release:

bunx bunner workspace:web          # build just the web app
bunx bunner "workspace:(web|docs)" # build multiple apps via regex
bunx bunner deploy                 # build everything, then deploy

Chaining smoke + e2e suites

You can resolve dependencies by name ("build:api") or by pattern (/^build:/). That makes it easy to reuse graphs for test pipelines.

const root = new Node({ name: "bunner" });

const build = root.child(new Command({ name: "build", command: ["bun", "run", "build"] }));

const smoke = root.child(
  new Command({
    name: "smoke",
    command: ["bun", "run", "test", "--", "--runInBand"],
    dependencies: [build],
  }),
);

root.child(
  new Command({
    name: "e2e",
    command: ["bun", "run", "playwright", "test"],
    dependencies: [smoke],
  }),
);

Execute only smoke tests during PRs, then chain the e2e suite on main:

# Pull request checks
bunx bunner "smoke"

# Nightly or main-branch jobs
bunx bunner e2e

CLI reference

| Flag | Description | | ---- | ----------- | | -f, --file <path> | Path to the bunner definition file. Defaults to bunner.ts in the current working directory. | | -n, --dry-run | Print the Graphviz DOT for the execution plan instead of running commands. | | patterns | Optional positional arguments treated as regular expressions. Each expression selects matching nodes (e.g. build, ci:.*, .*:deploy). If omitted, bunner prints the available node names. |

bunner executes the resolved nodes in parallel and stops the moment one fails. When commands are running, a prefixed, colored stream makes it easy to follow mixed stdout/stderr:

[green lint]: Running biome ci
[yellow test]: PASS lib/node.test.ts

Previewing the graph

Use --dry-run to inspect what would run:

bunx bunner publish --dry-run

The output is pure DOT, so you can visualize it directly with Graphviz:

bunx bunner publish --dry-run | dot -Tpng > graph.png

Authoring nodes

  • Node represents a namespace in the graph. Nodes can depend on other nodes by reference, by name, or by regular expression. When you call node.child(...), the child is automatically registered under the root so it can be located later.
  • Command extends Node and schedules a real process. It accepts command (string[]), optional cwd, and environment overrides. Standard output and error are piped back to the CLI with the node's color.

Under the hood, dependencies are resolved breadth-first and executed with Promise.all, so unrelated branches of your graph run concurrently. If a dependency fails, its parents are marked as failed without running their commands.

Development

bun install   # install dependencies
bun test      # run the library test suite
bun run biome # run the linter

License

Released under the BSD 3-Clause license. See LICENSE for details.