shiplet
v0.2.2
Published
Docker/Podman-powered dev environment CLI for Node.js — with release pipeline, snapshots, health dashboard, and more.
Downloads
323
Maintainers
Readme
🌊 Shiplet
A Docker/Podman-powered development environment CLI for Node.js and PHP/Composer projects — inspired by Laravel Sail, built for both ecosystems with a built-in web dashboard, release pipeline, and more.
No Docker expertise required. One command scaffolds a fully-containerised project with databases, mail, object storage, web dashboard, and more — for both Node.js and PHP.
Table of Contents
- 🌊 Shiplet
- Table of Contents
- Features
- Quick Start
- Installation
- Initialising a Project
- Container Runtimes
- Starting and Stopping
- Running Commands
- Databases
- Additional Services
- Testing
- Linting
- Web Dashboard
- Logs
- Container Management
- Volume Snapshots
- Environment Variables
- Health & Diagnostics
- Sharing Your App
- Customisation
- Examples
- CLI Reference
- Configuration Reference
- Requirements
- License
- Vite Projects
- Bun Projects
Features
| | Feature | Details |
| --- | --------------------- | ------------------------------------------------------------------------------ |
| 🟢 | Node.js + PHP | Express, Fastify, NestJS, Next.js, Nuxt, Laravel, Symfony, WordPress, and more |
| 🐳 🦭 | Docker + Podman | Auto-detected at startup; switch instantly with shiplet runtime switch |
| 🖥️ | Web Dashboard | Live metrics, log streaming, env editor, prune UI at http://localhost:6171 |
| 🚀 | Release Pipeline | Semver bump → changelog → git tag → container build → push → npm publish |
| 🔬 | Doctor | Full environment diagnostic before you hit a wall |
| 💾 | Snapshots | Named volume backups and restores — share dev databases with your team |
| 🧹 | Prune | Clean up containers / images / volumes interactively |
| 📋 | Shell Completions | Tab completions for bash, zsh, fish |
| 🧪 | 215 Tests | Full Jest suite — unit + integration, 80% coverage |
Quick Start
# Node.js
cd my-node-app
npx shiplet init
shiplet up -d
shipletlet npm install
shipletletlet logs -f
# PHP / Laravel (auto-detected)
cd my-laravel-app
npx shiplet init
shipletletlet up -d
shiplet composer install
shiplet artisan migrate
shiplet dashboard # → http://localhost:6171Installation
Zero-install via npx
npx shiplet initGlobal install
npm install -g shipletDev dependency
npm install --save-dev shipletShell alias (recommended)
Add to ~/.zshrc or ~/.bashrc:
alias shiplet='npx shiplet'Initialising a Project
shiplet initThe interactive wizard detects your language, framework, package manager, and existing lock files automatically. Answer the prompts and Shiplet writes everything you need.
Node.js templates
| Template | Description |
| --------- | ------------------------------------------ |
| express | Express.js REST API |
| fastify | Fastify with plugins |
| nestjs | NestJS with TypeScript |
| nextjs | Next.js (App Router) |
| nuxt | Nuxt 3 |
| t3 | T3 Stack (Next + tRPC + Prisma + Tailwind) |
| blank | Bare Node.js |
Package managers: npm · yarn · pnpm — auto-detected from lock files.
PHP templates
| Template | Description |
| ----------- | ------------------------------------------------------ |
| laravel | Laravel 11 — Artisan, queues, scheduler via Supervisor |
| symfony | Symfony 7 — console commands, Doctrine |
| wordpress | WordPress + WP-CLI |
| slim | Slim Framework 4 |
| lumen | Lumen micro-framework |
| blank | Vanilla PHP |
PHP versions: 8.3 · 8.2 · 8.1 · 8.0 Web servers: nginx (recommended) · apache
Skip prompts
# Node.js defaults
shiplet init --yes
shiplet init --template nestjs --yes
# PHP with specific options
shiplet init --language php --template laravel --php-version 8.3 --yes
shipletlet init --language php --template symfony --runtime podman --yesGenerated files — Node.js
shiplet.yml ← Docker Compose file
shiplet.config.json ← Shipletproject config
.shiplet/
Dockerfile ← App container
.env ← Environment variablesGenerated files — PHP
shiplet.yml ← Docker Compose (FPM + nginx/apache + services)
shiplet.config.json ← Shipletproject config
.shiplet/
Dockerfile ← PHP-FPM container (php-ext, Composer, WP-CLI)
nginx/default.conf ← Nginx vhost with correct document root
php/php.ini ← Development-optimised PHP config
supervisor/supervisord.conf ← Queue workers + scheduler (Laravel only)
.env ← Framework-aware env varsContainer Runtimes
Shiplet supports both Docker and Podman — the runtime is resolved in this priority order:
SHIPLET_RUNTIMEenvironment variableruntimefield inshiplet.config.json- Auto-detect: Podman wins if available and running, otherwise Docker
# Override for one command
SHIPLET_RUNTIME=podman shiplet up -d
SHIPLET_RUNTIME=docker shiplet build
# Permanently switch (writes shiplet.config.json)
shiplet runtime switch
# Check both runtimes
shiplet runtime show # which is active and why
shiplet runtime check # binary + daemon + compose plugin status for bothPodman notes
- Rootless by default — no daemon, no root required
- Requires
podman compose(bundled in Podman ≥ 4.7) orpodman-compose - Install:
pip3 install podman-composeor update Podman - If you see volume permission errors:
podman system migrate
Starting and Stopping
shiplet up # Start, stream output
shiplet up -d # Start in background (detached)
shiplet up --build # Rebuild images first
shiplet down # Stop and remove containers (data volumes preserved)
shiplet down -v # ⚠ Also remove volumes (deletes all data)
shiplet build # Rebuild images
shiplet build --no-cache # Full rebuild without layer cache
shiplet status # Show running containers + ports (alias: shiplet ps)Running Commands
Node.js
shiplet node --version
shiplet node scripts/seed.js
shiplet npm install
shiplet npm run dev
shiplet npm run build
shiplet yarn add lodash
shiplet pnpm install
shiplet npx prisma migrate dev
shiplet npx ts-node src/server.ts
shiplet exec app node -e "console.log('hello')"
shiplet exec redis redis-cli info
shiplet shell # bash/sh into 'app' container
shiplet shell postgresPHP / Composer Support
Composer
shiplet composer install
shiplet composer require laravel/sanctum
shiplet composer update
shiplet composer dump-autoload
shiplet composer show --installedPHP binary
shiplet php --version
shiplet php -r "echo phpversion();"
shiplet php scripts/seed.phpLaravel Artisan
shiplet artisan migrate
shiplet artisan migrate:fresh --seed
shiplet artisan key:generate
shiplet artisan make:model Product -mcr
shiplet artisan queue:work
shiplet artisan schedule:work
shiplet artisan tinker
shiplet artisan route:list
shiplet artisan config:cacheSymfony Console
shiplet console doctrine:migrations:migrate
shiplet console make:entity Product
shiplet console cache:clear
shiplet console debug:router
shiplet console assets:installWP-CLI
shiplet wp --info
shiplet wp plugin install woocommerce --activate
shiplet wp theme list
shiplet wp post list
shiplet wp user create admin [email protected] --role=administratorDatabases
shiplet db # Auto-detect running DB and open CLI
shiplet db postgres # → psql
shiplet db mysql # → mysql CLI
shiplet db mongo # → mongosh
shiplet db redis # → redis-cli
shiplet db mariadb # → mysql CLIAdditional Services
shiplet add # Interactive picker
shiplet add redis mailpit # Add specific services
shiplet add elasticsearch adminer| Service | Image | Purpose |
| --------------- | ------------------ | ------------------------------------ |
| postgres | postgres:16-alpine | PostgreSQL 16 |
| mysql | mysql:8.0 | MySQL 8 |
| mongo | mongo:7 | MongoDB 7 |
| redis | redis:7-alpine | Redis 7 |
| mailpit | axllent/mailpit | Email preview (SMTP trap) |
| minio | minio/minio | S3-compatible object storage |
| elasticsearch | elasticsearch:8 | Full-text search |
| adminer | adminer | Database web GUI |
| phpmyadmin | phpmyadmin | MySQL/MariaDB web GUI (PHP projects) |
After adding services, rebuild:
shiplet up --buildTesting
shiplet test # Auto-detects runner
shiplet test --coverage
shiplet test --watch
shiplet test src/user.test.tsDetection order: vitest → jest → mocha → tap → npm test
Shiplet's own test suite
npm test # All tests + coverage report
npm run test:unit # Unit tests only
npm run test:integration # Integration tests only
npm run test:watch # Watch mode215 tests, 6 files, ~80% coverage:
tests/
├── unit/
│ ├── helpers.test.js (22 tests) Core utilities
│ ├── helpers-extended.test.js (40 tests) Runtime, output, cache
│ ├── templates-node.test.js (35 tests) Node.js templates
│ ├── templates-php.test.js (52 tests) PHP templates + all frameworks
│ └── release-semver.test.js (30 tests) Semver + conventional commits
└── integration/
└── init-generation.test.js (41 tests) Full file generation E2ELinting
shiplet lint # Run all detected linters
shiplet lint --fix # Auto-fix where possibleAuto-detected (in order):
| Tool | Detected by |
| ---------- | --------------------------------------------------- |
| Biome | biome.json or devDependencies["@biomejs/biome"] |
| OXLint | devDependencies["oxlint"] |
| ESLint | .eslintrc*, eslint.config.* |
| Prettier | .prettierrc*, prettier.config.* |
| TypeScript | tsconfig.json → runs tsc --noEmit |
Web Dashboard
shiplet dashboard # Launch at http://localhost:6171
shiplet ui # Alias
shiplet dashboard --port 8080 # Custom port
shiplet dashboard --no-open # Don't auto-open browser
SHIPLET_UI_PORT=9000 shiplet dashboardSections
| Section | What you can do |
| --------------- | -------------------------------------------------------------------- |
| Overview | Live CPU%, memory bars, net I/O per container; system info |
| Projects | All shiplet projects on your machine — Up / Down / Build per project |
| Containers | Full list with search, start / stop / restart / remove per container |
| Images | Image inventory, per-image delete, prune dangling |
| Volumes | Volume list, per-volume delete, prune unused |
| Networks | Network list, prune unused |
| Logs | Live WebSocket log streaming — select any container, follow toggle |
| Release | Visual release wizard with commit breakdown and copy-to-clipboard |
| Environment | Per-project .env editor — add / edit / delete keys inline |
| Prune | One-click cleanup cards for every resource type |
| Settings | Runtime switcher, CLI quick-reference (click to copy) |
Stats update every 3 seconds via WebSocket. Log streaming is instant.
Logs
shiplet logs # All services, last 100 lines
shiplet logs -f # Follow all logs
shiplet logs app # One service
shiplet logs -f nginx # Follow nginx
shiplet logs -n 200 app # Last 200 linesContainer Management
# Port mappings
shiplet port # All services
shiplet port nginx # One service
shiplet port --check # Warn about host-port conflicts
# Live process table (refreshes every 2 s)
shiplet top # Auto-pick container
shiplet top app # Specific service
shiplet top --once # Print once, exit
# Scale replicas
shiplet scale app=3
shiplet scale app=2 worker=4
# Copy files (use service:path notation)
shiplet cp app:/var/www/html/storage/logs/app.log ./app.log
shiplet cp ./config/local.json app:/var/www/html/config/
shiplet cp postgres:/var/lib/postgresql/data/pg_hba.conf .
# Health dashboard
shiplet health # One-shot
shiplet health --watch # Refresh every 3 sVolume Snapshots
shiplet snapshot save before-migration # Backup all volumes
shiplet snapshot list # List saved snapshots
shiplet snapshot restore before-migration # Restore (interactive picker if omitted)
shiplet snapshot delete before-migration # Delete a snapshotStored in .shiplet/snapshots/ as compressed tarballs — one file per volume. Works with both Docker and Podman.
Steps
- Pre-flight checks (git repo, clean tree, on main/master, package.json)
- Test suite (inside container)
- Version bump (
package.json+package-lock.json) CHANGELOG.md— generated from conventional commits since last taggit commit+ annotatedgit tag- Container image build (tagged with version)
git push --tagsnpm publish(opt-in with--publish)
Flags
--dry-run Simulate without mutations
--yes Skip confirmation
--force Ignore branch/clean-tree checks
--pre <tag> Pre-release suffix (alpha, beta, rc)
--skip-tests Skip test run
--skip-build Skip container rebuild
--skip-push Skip git push
--publish Also npm publish
--access <level> public | restrictedConventional commits → changelog
feat(api): add pagination → 🚀 Features
fix(db): null result crash → 🐛 Bug Fixes
perf(cache): use LRU → ⚡ Performance
docs: update README → 📝 Documentation
feat!: redesign public API → 💥 Breaking Changes
chore: bump dependencies → 🔨 Chores
ci: update pipeline → 🤖 CI/CDEnvironment Variables
shiplet env list # All .env variables
shiplet env get DATABASE_URL # One variable
shiplet env set NODE_ENV production # Set variable
shiplet env set KEY=value # Alternative syntax
shiplet env unset OLD_KEY # Remove variable
shiplet env sync # Sync from .env.example → .envHealth & Diagnostics
Doctor
shiplet doctorChecks: Node.js version · Docker/Podman install + daemon · compose plugin · shiplet.yml syntax · package.json validity · .env vs .env.example completeness · port conflicts · disk space · dangling images.
Prune
shiplet prune # Interactive picker
shiplet prune containers # Remove stopped containers
shiplet prune images # Remove dangling images
shiplet prune volumes # Remove unused volumes
shiplet prune networks # Remove unused networks
shiplet prune all # System prune — everything unused
shiplet prune images --force # Skip confirmationSharing Your App
shiplet share # Tunnel port 3000 via localtunnel
shiplet share --port 4000 # Custom port
shiplet share --subdomain my-demo # Request subdomainCustomisation
shiplet publish # Eject .shiplet/Dockerfile → docker/DockerfileUpdate shiplet.yml to point at the ejected file:
services:
app:
build:
context: .
dockerfile: docker/DockerfileShiplet is just a thin wrapper over Compose — any valid Docker Compose V2 configuration works in shiplet.yml.
Examples
Four complete, runnable example projects ship in the examples/ directory.
examples/express-docker
Express.js REST API on Docker — PostgreSQL, Redis, Mailpit, Adminer.
cd examples/express-docker
shiplet up -d
shiplet npm install
shiplet exec app node src/db/migrate.js
# → http://localhost:3000
# → http://localhost:8025 (Mailpit)
# → http://localhost:8080 (Adminer)examples/fastify-podman
Fastify ESM API on Podman — MongoDB, Redis, MinIO, Mailpit. Includes: Swagger UI, JWT auth, S3 file uploads, Mongoose models.
cd examples/fastify-podman
SHIPLET_RUNTIME=podman shiplet up -d
shiplet npm install
# → http://localhost:3000/docs (Swagger)
# → http://localhost:9001 (MinIO console)examples/laravel-docker
Laravel 11 on Docker — MySQL, Redis, Mailpit, MinIO. Includes: Supervisor workers + scheduler, queue processing.
cd examples/laravel-docker
shiplet up -d
shiplet composer create-project laravel/laravel . --prefer-dist
shiplet artisan key:generate
shiplet artisan migrate
# → http://localhost
# → http://localhost:8025 (Mailpit)
# → http://localhost:9001 (MinIO)examples/symfony-podman
Symfony 7 on Podman — PostgreSQL, Redis, Mailpit.
cd examples/symfony-podman
SHIPLET_RUNTIME=podman shiplet up -d
shiplet composer create-project symfony/skeleton . "7.*"
shiplet console doctrine:database:create
# → http://localhostCLI Reference
┌─ Lifecycle ──────────────────────────────────────────────────────────────────
│ shiplet init [options] Interactive project setup
│ --language <l> node | php
│ --template <t> Framework template
│ --php-version <v> 8.3 | 8.2 | 8.1 | 8.0
│ --runtime <r> docker | podman
│ --yes Skip all prompts
│
│ shiplet up [-d] [--build] Start containers
│ shiplet down [-v] Stop (−v removes volumes)
│ shiplet build [--no-cache] Rebuild images
│ shiplet status | ps List services + ports
│
├─ Execution ──────────────────────────────────────────────────────────────────
│ shiplet shell [svc] Interactive shell (default: app)
│ shiplet exec <svc> [cmd...] One-off command in container
│ shiplet cp <src> <dest> Copy files (service:path syntax)
│
├─ Node.js ───────────────────────────────────────────────────────────────────
│ shiplet node / npm / npx / yarn / pnpm [args...]
│
├─ PHP ───────────────────────────────────────────────────────────────────────
│ shiplet composer [args...] Composer commands
│ shiplet php [args...] PHP binary
│ shiplet artisan [args...] Laravel Artisan shortcut
│ shiplet console [args...] Symfony console shortcut
│ shiplet wp [args...] WP-CLI shortcut
│
├─ Quality ───────────────────────────────────────────────────────────────────
│ shiplet test [args...] Run tests (auto-detected runner)
│ shiplet lint [--fix] Run linters (auto-detected)
│
├─ Database ──────────────────────────────────────────────────────────────────
│ shiplet db [service] Open DB CLI (auto-detected)
│
├─ Observability ─────────────────────────────────────────────────────────────
│ shiplet logs [-f] [-n N] [svc] View / follow container logs
│ shiplet health [--watch] Container health dashboard
│ shiplet top [svc] [--once] Live process table
│ shiplet port [svc] [--check] Port mappings + conflict check
│ shiplet status | ps Running services
│
├─ Services ──────────────────────────────────────────────────────────────────
│ shiplet add [services...] Add services to shiplet.yml
│ shiplet scale <svc=n>... Scale replicas
│ shiplet share [--port] [--subdomain] Public tunnel
│
├─ Data ──────────────────────────────────────────────────────────────────────
│ shiplet snapshot save|restore|list|delete [name]
│ shiplet env get|set|unset|list|sync [key] [value]
│
├─ Release ───────────────────────────────────────────────────────────────────
│ shiplet release [patch|minor|major|x.y.z] [options]
│ --dry-run --yes --force --pre <tag>
│ --skip-tests --skip-build --skip-push
│ --publish --access <public|restricted>
│
├─ Runtime ───────────────────────────────────────────────────────────────────
│ shiplet runtime show|switch|check
│
├─ Maintenance ───────────────────────────────────────────────────────────────
│ shiplet doctor Environment diagnostic
│ shiplet prune [target] [-f] Remove unused resources
│ shiplet upgrade [--global] Upgrade shiplet
│ shiplet publish Eject Dockerfiles
│
├─ UI ─────────────────────────────────────────────────────────────────────────
│ shiplet dashboard | ui [-p port] [--no-open]
│
└─ Shell ──────────────────────────────────────────────────────────────────────
shiplet completions [bash|zsh|fish]Configuration Reference
shiplet.config.json
{
"language": "node", // "node" or "php"
"runtime": "docker", // "docker" or "podman"
"appName": "my-app",
"template": "express", // Framework template
"nodeVersion": "20", // Node.js version (node projects)
"packageManager": "npm", // npm | yarn | pnpm (node projects)
"phpVersion": "8.3", // PHP version (php projects)
"webServer": "nginx", // nginx | apache (php projects)
"port": 3000 // Host port
}Environment overrides
| Variable | Purpose |
| ----------------- | ------------------------------------------- |
| SHIPLET_RUNTIME | Force docker or podman for all commands |
| SHIPLET_UI_PORT | Default port for shiplet dashboard |
Requirements
- Node.js ≥ 16 on the host (the
shipletCLI itself — your app runs inside the container) - One of:
- Docker Desktop (macOS / Windows) or Docker Engine + Compose plugin (Linux) → Get Docker
- Podman ≥ 4.7 (rootless, no daemon needed) → Get Podman
License
MIT © Shiplet Contributors
Vite Projects
Shiplet auto-detects Vite projects from package.json dependencies and sets up HMR correctly inside Docker/Podman.
# In an existing Vite project
shiplet init # detects react-swc-ts, vue-ts, svelte, astro, etc.
# Brand new Vite project
npx create-vite my-app --template react-swc-ts
cd my-app
shiplet init # language: Vite auto-selected
shiplet up -d
shiplet pnpm install
# → http://localhost:5173 with full HMRSupported Vite templates
| Template | Framework |
| ------------------------------------ | -------------------- |
| react / react-ts | React (Babel) |
| react-swc / react-swc-ts | React + SWC (faster) |
| vue / vue-ts | Vue 3 |
| svelte / svelte-ts / sveltekit | Svelte / SvelteKit |
| solid / solid-ts | Solid.js |
| preact / preact-ts | Preact |
| qwik / qwik-ts | Qwik |
| lit / lit-ts | Lit |
| vanilla / vanilla-ts | Plain JS/TS |
| astro | Astro (port 4321) |
| remix / remix-ts | Remix |
Critical vite.config setting
Add this to vite.config.ts for HMR to work inside Docker:
server: {
host: '0.0.0.0', // listen on all container interfaces
port: 5173,
hmr: {
host: 'localhost', // browser connects to localhost
port: 5173,
},
watch: {
usePolling: true, // required in Docker volumes on some OSes
interval: 300,
},
}shiplet init prints this snippet automatically. The examples/react-vite-ts/ example has it pre-configured.
Bun Projects
Bun is detected from bun.lockb or bun.lock files. The container uses the official oven/bun image.
# In an existing Bun project
shiplet init # auto-detects bun-hono, bun-elysia, bun-react, bun-api
# Brand new project
mkdir my-hono && cd my-hono
bun init
bun add hono
shiplet init # language: Bun → template: bun-hono
shiplet up -d
shiplet bun install
# → http://localhost:3000Bun commands
shiplet bun install # Install dependencies
shiplet bun add hono # Add a package
shiplet bun remove lodash # Remove a package
shiplet bun run dev # Run dev server
shiplet bun run build # Build
shiplet bun test # Run tests via Bun's built-in runner
shiplet bun --version # Check Bun version in containerSupported Bun templates
| Template | Description |
| ------------ | ----------------------------- |
| bun-blank | Bare Bun script |
| bun-api | Bun HTTP server (Bun.serve) |
| bun-hono | Hono framework |
| bun-elysia | ElysiaJS |
| bun-react | React with Bun bundler |
Bun version
The container uses BUN_VERSION=latest by default. Pin it in shiplet.yml:
services:
app:
build:
args:
BUN_VERSION: "1.1.21"