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

missbetty

v1.7.0

Published

Local Docker development domains through one Traefik switchboard

Readme

Betty

Betty Logo

Betty is a lightweight CLI for local Docker development domains. It links running Docker containers to local domains through one global Traefik reverse proxy, with HTTPS certificates generated by mkcert when available.

The name is inspired by a 1950s telephone switchboard operator: Betty does not become your reverse proxy. She links local domains to running containers and keeps proxy infrastructure out of individual projects.

Betty currently orchestrates:

  • Docker
  • Docker Compose
  • one global Traefik proxy
  • mkcert for local HTTPS certificates

Status

Betty is an early prototype. The current goal is a small, Valet-like workflow:

betty project load
betty project create
betty project link
betty project stop
betty project status
betty serve
betty link
betty relink
betty status
betty doctor
betty setup
betty setup --fix
betty unlink
betty stop
betty rest

The core workflow does not require a project configuration file. Start your containers with Docker or Docker Compose, then let Betty link them to local domains. Projects that want a single command can add .betty.yml and run betty project load.

Requirements

  • Node.js 24 or newer
  • Docker with Docker Compose
  • Access to the Docker socket
  • mkcert for HTTPS support

On Linux, macOS, WSL, and devcontainers, Betty expects Docker commands such as docker ps and docker compose version to work from the shell where Betty runs.

Installation

Install without Node.js or npm

Betty publishes standalone binaries on GitHub Releases. The installer scripts verify SHA256 checksums before installation. Release assets are also signed with Sigstore Cosign (keyless certificates).

Current prebuilt targets:

  • Linux x64
  • Linux arm64
  • macOS x64
  • macOS arm64
  • Windows x64
  • Windows arm64

Linux/macOS:

curl -fsSL https://raw.githubusercontent.com/mcKanses/missbetty/main/install.sh | sudo sh

Windows PowerShell:

irm https://raw.githubusercontent.com/mcKanses/missbetty/main/install.ps1 | iex

Optional version pinning:

BETTY_VERSION=v1.6.0 curl -fsSL https://raw.githubusercontent.com/mcKanses/missbetty/main/install.sh | sh
$env:BETTY_VERSION = 'v1.6.0'; irm https://raw.githubusercontent.com/mcKanses/missbetty/main/install.ps1 | iex

Windows installer options:

  • Skip dependency installation (Docker/mkcert):
$env:BETTY_SKIP_DEPS = 'true'; irm https://raw.githubusercontent.com/mcKanses/missbetty/main/install.ps1 | iex
  • Increase Docker daemon wait timeout (seconds, default 240, minimum 30):
$env:BETTY_DOCKER_WAIT_SECONDS = '420'; irm https://raw.githubusercontent.com/mcKanses/missbetty/main/install.ps1 | iex

The binary install path is:

  • Linux/macOS: /usr/local/bin/betty (or $BETTY_INSTALL_DIR/betty)
  • Windows: %LOCALAPPDATA%\\Programs\\betty\\betty.exe (or $env:BETTY_INSTALL_DIR\\betty.exe)

You still need runtime tools for Betty workflows (Docker and optionally mkcert), but Node.js and npm are no longer required for using Betty.

Uninstall standalone binary

Linux/macOS:

curl -fsSL https://raw.githubusercontent.com/mcKanses/missbetty/main/uninstall.sh | sh

Windows PowerShell:

irm https://raw.githubusercontent.com/mcKanses/missbetty/main/uninstall.ps1 | iex

Install from source (Node.js + npm)

From this repository:

npm install
npm run build
npm link

After npm link, the CLI is available as:

betty --help

Quick Start

For project-level orchestration, add .betty.yml to the project root:

project: my-app

up:
  command: docker compose up --build -d

down:
  command: docker compose down

domains:
  - host: my-app.dev
    target: http://127.0.0.1:3000

https:
  enabled: true
  certificateAuthority: missbetty

permissions:
  hosts: prompt
  trustStore: prompt
  docker: allowed

Then start the project:

betty project load

Betty prepares the local route and prints the available URLs:

https://my-app.dev

For the lower-level workflow, start the global proxy once, start your containers yourself, then link a running container:

betty serve
betty link my-app --domain my-app.localhost --port 3000

Commands

betty project

Manages project-level orchestration from .betty.yml.

betty project load

Reads .betty.yml, prepares hosts entries and mkcert certificates, starts Betty's global proxy, writes project routes, runs the configured up.command, then prints the available URLs. Loopback targets such as 127.0.0.1 and localhost are routed through host.docker.internal inside the Traefik container.

betty project load
betty project load --file ./.betty.yml
betty project load --dry-run
betty project load -y

Example .betty.yml:

project: mckanses-auth

up:
  command: docker compose --env-file .env -f compose.yml -f compose.override.yml up --build -d

down:
  command: docker compose -f compose.yml -f compose.override.yml down

domains:
  - host: my-app.dev
    target: http://127.0.0.1:5173

  - host: api.my-app.dev
    target: http://127.0.0.1:8080

https:
  enabled: true
  certificateAuthority: missbetty

permissions:
  hosts: prompt
  trustStore: prompt
  docker: allowed

Config fields:

| Field | Description | | --- | --- | | project | Stable project name used for Betty route file names | | up.command | Shell command run after hosts, certificates, and proxy routes are ready | | down.command | Shell command run on project stop | | domains[].host | Local domain Betty should expose | | domains[].target | Local HTTP(S) target for the domain, for example http://127.0.0.1:5173 | | https.enabled | Enables HTTPS routes and mkcert certificates | | https.certificateAuthority | Currently supports missbetty | | permissions.hosts | prompt, allowed, manual, or denied for hosts-file changes | | permissions.trustStore | prompt, allowed, manual, or denied for mkcert CA setup | | permissions.docker | prompt, allowed, manual, or denied for Docker commands |

betty project create

Creates a new .betty.yml interactively.

betty project create
betty project create --name my-app

betty project link

Links project domains to the Betty proxy without running the up.command. Auto-detects .betty.yml in the current directory.

betty project link
betty project link --file ./.betty.yml
betty project link -y

betty project stop

Runs the configured down.command and removes all domain links for the project. Auto-detects .betty.yml in the current directory.

betty project stop
betty project stop --file ./.betty.yml
betty project stop -y

betty project status

Shows which project domains are currently linked. Auto-detects .betty.yml in the current directory, or accepts --name to look up a project by name.

betty project status
betty project status --file ./.betty.yml
betty project status --name my-app

betty dev (legacy)

betty dev is a legacy alias for betty project load. Use betty project load instead.

betty serve

Starts Betty's global local switchboard service.

It creates:

  • ~/.betty
  • ~/.betty/docker-compose.yml
  • ~/.betty/dynamic
  • ~/.betty/certs
  • Docker network betty_proxy
  • Traefik container betty-traefik

Traefik publishes HTTP on host port 80 and HTTPS on host port 443 by default. Both ports must be available on the host while Betty is running.

If another local proxy already holds 80/443, you can publish Betty on different host ports via the BETTY_HTTP_PORT / BETTY_HTTPS_PORT environment variables, or by adding httpPort / httpsPort to ~/.betty/config.json. Traefik still listens on 80/443 inside the container, so routing and certificates are unaffected — but non-default ports mean URLs need an explicit port, e.g. https://my-app.dev:8443.

Betty keeps routing config globally in ~/.betty/dynamic, and local certificates in ~/.betty/certs, so individual projects do not need Betty-specific files.

Betty also maintains ~/.betty/links.json — the source container for each linked route, written when you link and pruned when you unlink — and, when you change settings, ~/.betty/config.json. Commands that change this shared state (serve, link, relink, unlink, dev/project) take a short exclusive lock on ~/.betty, so running two Betty commands at once is refused with a "please retry" hint instead of corrupting the files.

betty stop

Stops Betty's global local switchboard service.

betty rest is available as a legacy alias with the same behavior.

It runs Docker Compose down against Betty's global compose file:

~/.betty/docker-compose.yml

betty status

Shows Betty's proxy status and linked domains.

betty status
betty status --short
betty status --long
betty status --json

| Option | Description | | --- | --- | | --long | Show detailed proxy container info | | --short | Show a compact linked-domain table | | --json | Output status as JSON | | --format <format> | Output format, for example json |

betty link [container]

Links a running container to a local domain.

betty link my-container --domain my-app.localhost --port 3000

If required values are missing, Betty asks interactively for:

  • container
  • domain
  • internal container port

Betty links the container into the global Docker network betty_proxy, writes a route file to ~/.betty/dynamic, and reloads the global Traefik container. If mkcert is installed, Betty also creates a certificate in ~/.betty/certs and enables HTTPS for the linked domain.

Use .localhost domains when possible, for example my-app.localhost. Betty also accepts custom domains such as .dev and can add an append-only hosts entry for them. Browsers require HTTPS for some TLDs, including .dev, so mkcert should be installed before linking those domains.

| Option | Description | | --- | --- | | --domain <domain> | Target domain, for example my-app.localhost | | --port <port> | Internal container port | | --dry-run | Preview planned changes without applying them | | --open | Open the linked domain in the browser after linking |

betty relink [target]

Updates an existing local domain link.

Use it when the container, domain, or internal port changes:

betty relink
betty relink my-app --port 5173
betty relink --domain my-app.example.dev
betty relink my-app.localhost --container new-container --port 3000

If values are missing, Betty asks interactively. When the domain changes to a custom domain outside .localhost, Betty attempts to add a new append-only hosts entry. It does not remove the previous hosts entry.

| Option | Description | | --- | --- | | --container <container> | New target container | | --domain <domain> | New linked domain | | --port <port> | New internal container port |

betty unlink [target]

Removes an existing local domain link.

betty unlink my-app.localhost
betty unlink --domain my-app.localhost
betty unlink --all

For custom domains that are not under .localhost, betty unlink removes the hosts entry when no other link uses the same domain. If removal fails, Betty prints the domain so you can remove it manually.

| Option | Description | | --- | --- | | --domain <domain> | Domain to unlink | | --all | Remove all links at once |

betty config [action] [key] [value]

Reads or updates Betty configuration.

betty config
betty config get <key>
betty config set <key> <value>

Supported keys: domainSuffix, httpPort, httpsPort.

betty config set domainSuffix .localhost
betty config set httpPort 8080
betty config set httpsPort 8443

Ports set here are also overridable per shell via the BETTY_HTTP_PORT / BETTY_HTTPS_PORT environment variables, which take precedence.

Development

npm install
npm run build
npm run lint
npm test
npm run test:serial
npm run test:coverage

The default test script runs Jest serially so it works in restricted environments that cannot spawn parallel Jest workers. Coverage also runs serially for the same reason.

Release

Development happens on development. Releases are published from main by GitHub Actions with semantic-release.

Use Conventional Commits so semantic-release can determine the next version:

fix: Repair npm package contents
feat: Add a new link option
feat!: Change the link command contract

Release behavior:

  • fix: creates a patch release
  • feat: creates a minor release
  • BREAKING CHANGE: or ! creates a major release
  • ci: and chore: do not trigger a release by default

Before merging to main, run the full local release check:

npm run release:check

After a merge to main, GitHub Actions runs semantic-release. If releasable commits exist, it creates the Git tag, GitHub release, and npm publish automatically without pushing a release commit back to main.

Configure the repository secret NPM_TOKEN with an npm automation or granular access token that can publish missbetty.

The publish workflow uses Node.js 24. Betty itself requires Node.js 24 or newer at runtime.

Manual fallback release scripts are still available:

npm run release:patch
npm run release:minor
npm run release:major

The fallback scripts are guarded and only run on the main branch.

For emergency manual publishing:

npm run release:publish

prepack builds the TypeScript output before npm creates the package. Keep the manual scripts as fallback only; the normal release path is semantic-release on main.

Devcontainer

This repository includes a devcontainer setup using Docker-outside-of-Docker. That means Node and TypeScript run inside the devcontainer, while Docker containers are created through the host Docker daemon.

This is suitable for CLI development and Docker orchestration tests. Host browser access to custom domains may still require host-specific handling for the hosts file.

Notes

Betty is not intended to replace Traefik, Caddy, nginx, or Docker Compose. Instead, Betty provides a small CLI layer around them for local development.

License

Betty is released under the MIT License. See LICENSE for the full terms.

Support Betty

If Betty saves you time, consider supporting development:

Support helps me work on:

  • WSL support improvements
  • TLS automation
  • better Docker integration

Future work may include:

  • cleaner persistent link state
  • optional project discovery

Troubleshooting

Port 443 is already in use

If betty serve reports a conflict on 443, list the containers using it:

docker ps --filter "publish=443" --format "table {{.Names}}\t{{.Ports}}"

If an old Traefik stack is still running, stop it:

docker stop traefik-traefik-1

Then run:

betty serve