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

shiplet

v0.2.0

Published

Docker/Podman-powered dev environment CLI for Node.js — with release pipeline, snapshots, health dashboard, and more.

Downloads

245

Readme

🌊 Shiplet

A lightweight, Docker-powered development environment for Node.js projects — inspired by Laravel Sail, built for the JS ecosystem.

No Docker knowledge required. One command gets you a fully containerised Node app with databases, mail, object storage, and more.


Table of Contents


Introduction

Shiplet is a CLI tool that wraps Docker Compose into a set of simple, memorable commands purpose-built for Node.js development. It is the spiritual equivalent of Laravel Sail for PHP, but designed with the Node.js ecosystem in mind:

  • Supports npm, yarn, and pnpm out of the box
  • Auto-detects your test runner (jest, vitest, mocha)
  • Auto-detects which database CLI to open (shiplet db)
  • Works with Express, Fastify, NestJS, Next.js, Nuxt, T3 via built-in templates
  • Includes an env command for full .env management
  • Can tunnel your local app to the internet with shiplet share
  • Runs via npx — no global install needed

At its core, Shiplet is a shiplet.yml (Docker Compose) file and a thin CLI wrapper. You can eject the Dockerfiles at any time with shiplet publish for full control.

Shiplet is supported on macOS, Linux, and Windows (via WSL2).


Quick Start

# In a new or existing Node.js project:
npx shiplet init

# Start everything
shiplet up -d

# Install your npm deps inside the container
shiplet npm install

# Open a shell
shiplet shell

# Run your tests
shiplet test

Installation

Run via npx (zero-install)

The fastest way to initialise Shiplet in any project — no global install needed:

npx shiplet init

After init, all subsequent shiplet commands are available through ./node_modules/.bin/shiplet (if added as a dev dep) or globally.

Install globally

npm install -g shiplet
# or
yarn global add shiplet
# or
pnpm add -g shiplet

Add to an existing project

npm install --save-dev shiplet
npx shiplet init

Shell alias

To avoid typing ./node_modules/.bin/shiplet every time, add an alias to your shell config (~/.zshrc or ~/.bashrc):

alias shiplet='npx shiplet'

Or if installed locally in every project:

alias shiplet='./node_modules/.bin/shiplet'

Restart your shell, then you can simply type shiplet up, shiplet shell, etc.


Initialising a Project

Run the interactive setup wizard:

shiplet init

You will be prompted to choose:

| Option | Description | | ------------------- | ---------------------------------------------------------------------------------------- | | App name | Used as the Docker Compose project name | | Template | express, fastify, nestjs, nextjs, nuxt, t3, or blank | | Node version | 22, 20, or 18 (inside the container) | | Package manager | npm, yarn, or pnpm (auto-detected from lock files) | | Port | The host port your app will be accessible on | | Services | Any combination of postgres, mysql, mongo, redis, mailpit, minio, elasticsearch, adminer | | Timezone | Container timezone (default: UTC) |

To skip all prompts and use defaults:

shiplet init --yes
shiplet init --template nestjs --yes

After init, Shiplet creates:

your-project/
├── shiplet.yml              ← Docker Compose file (edit freely)
├── .env                  ← Environment variables (added to existing .env)
└── .shiplet/
    └── Dockerfile        ← App container Dockerfile

Starting and Stopping

Start all containers defined in shiplet.yml:

shiplet up

Start in detached (background) mode:

shiplet up -d

Start and force a rebuild of images first:

shiplet up --build

Once running, your app is accessible at http://localhost:3000 (or whichever port you chose).

Stop all containers (containers are removed, data volumes are preserved):

shiplet down

Stop and destroy all volumes (this deletes database data — use with caution):

shiplet down -v

Executing Commands

When using Shiplet, your application runs inside a Docker container. Shiplet provides shortcuts to run common commands without leaving your terminal.

Node.js commands

# Check the Node version inside the container
shiplet node --version

# Run a script
shiplet node scripts/seed.js

Package manager commands

Shiplet proxies all package manager commands into the app container:

# npm
shiplet npm install
shiplet npm run dev
shiplet npm run build

# yarn
shiplet yarn
shiplet yarn add express

# pnpm
shiplet pnpm install
shiplet pnpm add fastify

# npx (inside the container)
shiplet npx prisma migrate dev
shiplet npx ts-node src/server.ts

One-off exec

Run any command inside any running container:

shiplet exec app node -e "console.log('hello')"
shiplet exec redis redis-cli info
shiplet exec postgres psql -U shiplet -d app

Interactive shell

Open a bash shell inside the app container (falls back to sh if bash is unavailable):

shiplet shell

Open a shell in a different service:

shiplet shell postgres
shiplet shell redis

Running Tests

Shiplet automatically detects your test runner by inspecting devDependencies in package.json:

| Detected dependency | Command used | | --------------------- | ---------------- | | vitest | npx vitest run | | jest | npx jest | | mocha | npx mocha | | (none of the above) | npm test |

# Run all tests
shiplet test

# Pass flags through to your test runner
shiplet test --coverage
shiplet test --watch
shiplet test src/user.test.ts

Working with Databases

PostgreSQL

When Postgres is enabled, it runs in the postgres service. Your app connects to it at the host postgres (the Docker service name) on port 5432.

To connect from your machine (e.g. TablePlus or psql):

  • Host: localhost
  • Port: 5432 (or POSTGRES_PORT from .env)
  • User / Password / DB: as set in .env

Open the Postgres CLI inside the container:

shiplet db postgres
# or simply (auto-detected):
shiplet db

MySQL

MySQL runs in the mysql service. Connect your app using host mysql, port 3306.

shiplet db mysql
# or:
shiplet db

MongoDB

MongoDB runs in the mongo service. Your MONGODB_URI in .env is pre-configured to point at mongo:27017.

shiplet db mongo
# or:
shiplet db

Redis

Redis runs in the redis service. Connect your app using redis://redis:6379.

shiplet db redis
# or:
shiplet db

Tip: shiplet db with no argument auto-detects the first running database service.


Additional Services

Mailpit (email)

Mailpit intercepts all outgoing SMTP mail from your app and displays it in a web UI — no real emails are sent during development.

  • SMTP host/port: mailpit:1025
  • Web UI: http://localhost:8025

Configure your mailer (e.g. Nodemailer):

const transporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,   // mailpit
  port: process.env.SMTP_PORT,   // 1025
});

MinIO (S3)

MinIO provides an S3-compatible object storage API for local development.

  • API endpoint: http://minio:9000 (from inside containers), http://localhost:9000 (from host)
  • Console UI: http://localhost:9001

Configure the AWS SDK:

const s3 = new S3Client({
  endpoint: process.env.S3_ENDPOINT,  // http://minio:9000
  region: 'us-east-1',
  credentials: {
    accessKeyId: process.env.S3_ACCESS_KEY,
    secretAccessKey: process.env.S3_SECRET_KEY,
  },
  forcePathStyle: true,
});

Elasticsearch

Elasticsearch runs with security disabled for local development. Access it at http://elasticsearch:9200 from your app or http://localhost:9200 from your host.

Adminer (DB GUI)

Adminer is a lightweight browser-based database manager.

  • URL: http://localhost:8080
  • Works with PostgreSQL, MySQL, MongoDB, and more.

Adding Services Post-Init

You can add more services to an existing Shiplet project at any time:

# Interactive picker
shiplet add

# Add specific services directly
shiplet add redis mailpit
shiplet add elasticsearch adminer

Available services: postgres, mysql, mongo, redis, mailpit, minio, elasticsearch, adminer

After adding services, rebuild and restart:

shiplet up --build

Environment Variables

Shiplet includes a full .env management command.

# List all variables
shiplet env list

# Get a single variable
shiplet env get DATABASE_URL

# Set a variable
shiplet env set NODE_ENV production
shiplet env set DATABASE_URL=postgresql://shiplet:secret@postgres:5432/app

# Remove a variable
shiplet env unset OLD_KEY

# Sync missing keys from .env.example → .env
shiplet env sync

The sync action is particularly useful after pulling changes from git where .env.example has new keys.


Container Logs

# Tail the last 100 lines from all services
shiplet logs

# Follow (stream) logs in real time
shiplet logs -f

# Tail a specific service
shiplet logs app
shiplet logs postgres

# Show the last 50 lines
shiplet logs -n 50 app

Container Status

shiplet status
# or the alias:
shiplet ps

Displays a colourised table of all services, their status, and port mappings:

  NAME              STATUS         PORTS
  myapp-app-1       running (Up)   0.0.0.0:3000->3000/tcp
  myapp-postgres-1  running (Up)   0.0.0.0:5432->5432/tcp
  myapp-redis-1     running (Up)   0.0.0.0:6379->6379/tcp

Sharing Your App

Expose your local app to the internet using a secure tunnel:

shiplet share

This uses localtunnel and outputs a public URL that anyone can visit.

# Specify a port (default: 3000)
shiplet share --port 4000

# Request a specific subdomain
shiplet share --subdomain my-demo

Press Ctrl+C to stop sharing.


Rebuilding Images

After changing Node version, package manager, or editing .shiplet/Dockerfile:

shiplet build

Force a full rebuild without cache (useful after system package changes):

shiplet build --no-cache

Or rebuild on the next up:

shiplet up --build

Customisation (Ejecting)

Shiplet ships with a ready-made Dockerfile stored in .shiplet/Dockerfile. To gain full control, eject it to your project root:

shiplet publish

This copies the Dockerfile to docker/Dockerfile. You can then edit it freely — add system packages, change the base image, install global tools, etc.

Update shiplet.yml to point at the ejected file:

services:
  app:
    build:
      context: .
      dockerfile: docker/Dockerfile

Since Shiplet is just Docker Compose under the hood, any valid Compose configuration works in shiplet.yml.


Node Version

The Node.js version is set at build time via a Docker build argument. To change it, update shiplet.yml:

services:
  app:
    build:
      args:
        NODE_VERSION: "22"   # or "20", "18"

Then rebuild:

shiplet build --no-cache
shiplet up

Package Manager

The package manager is also baked into the image via corepack. To change it, update shiplet.yml:

services:
  app:
    build:
      args:
        PACKAGE_MANAGER: "pnpm"   # npm | yarn | pnpm

Rebuild the image after changing this.


Project Templates

When running shiplet init, you can select a project template:

| Template | Description | | --------- | ------------------------------------------------ | | blank | Bare Node.js container, no framework scaffolding | | express | Express.js with a minimal app structure | | fastify | Fastify with plugins pre-configured | | nestjs | NestJS with TypeScript | | nextjs | Next.js (App Router) | | nuxt | Nuxt 3 | | t3 | T3 stack (Next.js + tRPC + Prisma + Tailwind) |

Or pass via CLI flag:

npx shiplet init --template nestjs

Generated File Reference

shiplet.yml

The Docker Compose file for your project. Edit it directly to customise ports, add environment variables, mount extra volumes, or add any service available on Docker Hub.

.shiplet/Dockerfile

The Dockerfile for your app container. Contains the base Node image, timezone setup, and package manager initialisation. Eject with shiplet publish for full control.

.env

Shiplet appends its required variables to your .env file on init. Variables are namespaced to avoid collisions with your existing config.


Requirements

  • Docker Desktop (macOS / Windows) or Docker Engine + Compose plugin (Linux) — install here
  • Node.js ≥ 16 on the host (only needed to run the shiplet CLI itself — your app runs inside the container)

Container Runtime (Docker & Podman)

Shiplet supports both Docker and Podman as container runtimes. The runtime is auto-detected at startup — no configuration needed unless you want to pin one explicitly.

Auto-detection priority

  1. SHIPLET_RUNTIME=docker or SHIPLET_RUNTIME=podman environment variable
  2. runtime field in shiplet.config.json (set by shiplet init or shiplet runtime switch)
  3. Auto-detect: Podman wins if available and running, otherwise Docker

Runtime commands

# Show which runtime is active and why
shiplet runtime show

# Interactively switch between docker and podman
shiplet runtime switch

# Validate both runtimes — checks binary, daemon, and compose plugin
shiplet runtime check

Forcing a runtime for a single command

SHIPLET_RUNTIME=podman shiplet up -d
SHIPLET_RUNTIME=docker shiplet build --no-cache

Podman-specific notes

Shiplet uses podman compose (bundled in Podman ≥ 4.7) or falls back to the standalone podman-compose package. Install it with:

pip3 install podman-compose
# or update Podman to ≥ 4.7

Rootless Podman is fully supported. If you see permission errors on volume mounts, ensure your user has the correct subuid/subgid mappings:

podman system migrate

Release Pipeline

shiplet release is a complete, opinionated release pipeline that handles everything from pre-flight checks to git tagging and npm publishing.

Basic usage

# Bump patch version (1.0.0 → 1.0.1)
shiplet release

# Bump minor version (1.0.0 → 1.1.0)
shiplet release minor

# Bump major version (1.0.0 → 2.0.0)
shiplet release major

# Explicit version
shiplet release 2.4.0

# Pre-release tag (1.0.0 → 1.0.1-beta.0)
shiplet release patch --pre beta

# Release candidate
shiplet release minor --pre rc

Pipeline steps

Every shiplet release runs these steps in order:

| Step | Description | | --------------------- | -------------------------------------------------------------------------------- | | Pre-flight checks | Git repo exists, clean working tree, on main/master branch, package.json present | | Tests | Runs your test suite inside the container (auto-detects jest/vitest/mocha) | | Version bump | Updates package.json (and package-lock.json) to the new version | | Changelog | Generates/prepends CHANGELOG.md from conventional commits since the last tag | | Git commit + tag | git commit -m "chore(release): vX.Y.Z" and git tag -a vX.Y.Z | | Image build | Rebuilds your container image tagged with the new version | | Git push | git push && git push --tags | | npm publish | (optional, with --publish) Runs npm publish |

Dry run

See exactly what would happen without changing anything:

shiplet release minor --dry-run

Output includes a full changelog preview, version diff, and step-by-step simulation.

Flags reference

| Flag | Description | | ---------------- | ---------------------------------------------- | | --dry-run | Simulate without mutations | | --yes | Skip confirmation prompt | | --force | Skip branch + clean-tree enforcement | | --pre <tag> | Add pre-release suffix (alpha, beta, rc) | | --skip-tests | Skip the test suite | | --skip-build | Skip container image rebuild | | --skip-push | Skip git push | | --publish | Also run npm publish | | --access <lvl> | npm publish access: public or restricted |

Conventional commits

The changelog generator parses Conventional Commits:

feat(auth): add OAuth2 login          → 🚀 Features
fix(db): handle null result           → 🐛 Bug Fixes
perf(cache): use LRU eviction         → ⚡ Performance
refactor(api): simplify middleware    → ♻️  Refactoring
docs: update README                   → 📝 Documentation
feat!: redesign public API            → 💥 Breaking Changes

Non-conventional commits are grouped under 📌 Other.


Container Health Dashboard

# One-shot health view
shiplet health

# Auto-refresh every 3 seconds
shiplet health --watch

Displays a live table with per-service:

  • Status (running/starting/unhealthy — colour-coded)
  • CPU % (green < 40%, yellow < 80%, red > 80%)
  • Memory usage (current / limit)
  • Port mappings

Volume Snapshots

Back up and restore named Docker/Podman volumes at any time — useful before destructive migrations or sharing a dev database state with a colleague.

# Save a named snapshot of all volumes
shiplet snapshot save before-migration

# List all snapshots
shiplet snapshot list

# Restore a snapshot (interactive picker if name omitted)
shiplet snapshot restore before-migration

# Delete a snapshot
shiplet snapshot delete before-migration

Snapshots are stored in .shiplet/snapshots/ as compressed tarballs. Each volume gets its own file: <snapshot-name>-<volume-name>.tar.gz.


Linting

# Run all detected linters
shiplet lint

# Run linters and auto-fix where possible
shiplet lint --fix

Shiplet inspects your package.json and config files to detect and run:

| Tool | Config files detected | | -------------- | ------------------------------------- | | Biome | biome.json, biome.jsonc | | OXLint | devDependencies.oxlint | | ESLint | .eslintrc*, eslint.config.* | | Prettier | .prettierrc*, prettier.config.* | | TypeScript | tsconfig.json (runs tsc --noEmit) |

All linters run inside the container so the environment is consistent with CI.


Scaling Services

# Scale the app service to 3 replicas
shiplet scale app=3

# Scale multiple services at once
shiplet scale app=2 worker=4

# Scale back to 1
shiplet scale app=1

Uses docker/podman compose up --scale under the hood — containers are added/removed without recreating existing ones.


shiplet.config.json

shiplet stores project-level configuration in shiplet.config.json at the project root (alongside shiplet.yml). This file is safe to commit.

{
  "runtime": "podman",
  "appName": "my-app",
  "nodeVersion": "20",
  "packageManager": "pnpm",
  "port": 3000
}

| Key | Description | | ---------------- | ---------------------------------------------- | | runtime | Pinned container runtime: docker or podman | | appName | Used as the Docker Compose project name | | nodeVersion | Node.js version inside the app container | | packageManager | npm, yarn, or pnpm | | port | Host port the app is exposed on |

Override the runtime at any time without editing the file:

SHIPLET_RUNTIME=docker shiplet up

Web Dashboard

Launch a live web UI to manage all your containers, projects, and configuration:

shiplet dashboard
# or the alias:
shiplet ui

Opens http://localhost:6171 automatically.

Dashboard sections

| Section | What it shows | | -------------- | -------------------------------------------------------------------------------------------------------------------------------- | | Overview | Running/stopped containers with live CPU%, memory bars, network I/O, and port mappings. System info panel. | | Projects | Auto-scanned Shiplet projects. Per-project: services, runtime badge, version, Up/Down/Restart/Build buttons. | | Containers | All containers (including stopped) with searchable table, per-container start/stop/restart/remove actions. | | Images | All pulled images with repository, tag, size, and creation date. | | Volumes | Named volumes with driver and mount path. | | Logs | Live WebSocket log streaming — select any container, toggle follow mode, clear. | | Release | Visual release wizard: bump selector, pre-release tag, checkboxes for skip-tests/publish, dry-run preview with commit breakdown. | | Settings | Docker ↔ Podman runtime switcher. Per-project .env editor. CLI quick-reference grid. |

Options

# Custom port
shiplet dashboard --port 8080

# Don't auto-open browser
shiplet dashboard --no-open

# Or set via env
SHIPLET_UI_PORT=9000 shiplet dashboard

Live updates

The dashboard uses WebSockets for real-time data:

  • Container stats (CPU, memory, network) refresh every 3 seconds
  • Log streaming is live — tail any running container with zero latency
  • The green dot in the top bar shows the WebSocket connection status

Examples

Two complete example projects are included in the examples/ directory.

examples/express-docker

A production-ready Express.js REST API using the Docker runtime.

Services: PostgreSQL 16, Redis 7, Mailpit, Adminer

cd examples/express-docker
shiplet up -d
shiplet npm install
shiplet exec app node src/db/migrate.js
# App → http://localhost:3000
# Adminer → http://localhost:8080
# Mailpit → http://localhost:8025

Features: request logging (morgan), security headers (helmet), Redis caching with 60s TTL, PostgreSQL connection pooling, full CRUD /api/items.

examples/fastify-podman

A production-ready Fastify REST API (ESM) using the Podman runtime.

Services: MongoDB 7, Redis 7, MinIO (S3), Mailpit, Mongo Express

cd examples/fastify-podman
SHIPLET_RUNTIME=podman shiplet up -d
shiplet npm install
# App        → http://localhost:3000
# Swagger UI → http://localhost:3000/docs
# MinIO UI   → http://localhost:9001
# Mongo UI   → http://localhost:8081

Features: Swagger/OpenAPI docs, JWT authentication, Redis-cached paginated queries with tag/text search, S3-compatible file uploads via pre-signed URLs (MinIO), Mongoose models with indexes, graceful shutdown.

Running either example with the other runtime

Both examples work with either runtime — just override:

# Run the Docker example with Podman
cd examples/express-docker
SHIPLET_RUNTIME=podman shiplet up -d

# Run the Podman example with Docker
cd examples/fastify-podman
SHIPLET_RUNTIME=docker shiplet up -d

License

MIT © Anand Pilania