create-bunship

Scaffold and ship production-ready Bun monorepos using official framework scaffolders
1,553 4
Install
npm install create-bunship
Latest Version:0.6.0
License:MIT
Last Updated:Oct 16, 2026
Links: GitHub  ·  npm
Maintainer: ainmutaqorrobin

create-bunship

Scaffold a production-ready Bun monorepo in one command — and ship it. Instead of maintaining its own boilerplate, bunship orchestrates each framework's official scaffolder non-interactively, then wires a single coherent toolchain on top.

bun create bunship my-startup               # interactive
# or, fully non-interactive (AI-agent mode):
bunx create-bunship my-startup --web next --api nest --docker --cicd --json

Supported frameworks

Pick at most one per slot (none skips a slot). Apps are generated by the framework's own scaffolder, so they always match upstream output.

Slot Framework Flag Scaffolded with Dir Dev port
Web Next.js --web next create-next-app apps/web 3000
Web React + Vite --web react-vite create-vite (react-ts) apps/web 5173
Web Nuxt --web nuxt create-nuxt apps/web 3000
Mobile Expo --mobile expo create-expo-app apps/mobile 8081
API NestJS --api nest @nestjs/cli (nest new) apps/api 3001
API Express --api express built-in minimal TS template apps/api 3001
API Hono --api hono create-hono (bun template) apps/api 3001
API Fastify --api fastify fastify generate (ts) apps/api 3001

Each app is then patched to fit the monorepo: workspace package name (@<project>/<app>), non-conflicting dev ports, a /health endpoint on API stacks, and formatting normalized with oxfmt.

What you get after running it

my-startup/
├── apps/
│   ├── web/                 your chosen web framework (official scaffolder output)
│   ├── mobile/              Expo (if selected)
│   └── api/                 your chosen API framework
├── package.json             bun workspaces + scripts (below), engines pinned to Bun 1.3
├── .oxlintrc.json           linting (oxlint)
├── .oxfmtrc.json            formatting (oxfmt)
├── knip.json                unused files / exports / deps
├── .husky/                  pre-commit lint-staged · pre-push full check
├── .vscode/                 settings + recommended extensions
├── AGENTS.md + CLAUDE.md    conventions for AI coding agents
├── .gitignore · .gitattributes · .env.example · README.md
│
│   with --agents (default: claude):
├── scripts/agent-format.ts  oxlint --fix + oxfmt on every file an agent edits
├── .claude/settings.json    …and one tiny hook config per chosen agent
│
│   with --skills (default: stack):
├── .agents/skills/          SKILL.md best-practice playbooks per framework (+ .claude/skills, .windsurf/skills)
├── skills-lock.json         pinned sources + hashes: bunx skills update
│
│   with --docker:
├── apps/*/Dockerfile        per-app production images
├── compose.yaml             local prod-parity: bun run docker:prod
├── dev.Dockerfile           shared dev image (bun + node) for the dev stack
├── compose.dev.yaml         every app's dev server, hot reload: bun run docker:dev
│
│   with --cicd (implies --docker):
├── .github/workflows/       ci.yml (check + build) · deploy.yml (GHCR → SSH → compose)
└── deploy/                  VPS bundle: image-based compose, nginx + TLS, bootstrap guide

The generated root package.json gives you:

Script Does
bun run dev all dev servers via workspace filter
bun run dev:web / dev:api one app (one script per selected app)
bun run build build every app
bun run check lint + format:check + typecheck + knip
bun run lint / format oxlint / oxfmt (with :fix / :check variants)
bun run docker:dev every app in Docker with hot reload (--docker)
bun run docker:prod local prod-parity run of the images CI deploys

The CLI finishes by running git init, bun install, an oxfmt pass, and a first commit — so every generated repo passes bun run check and bun run build from its very first commit (enforced by this project's nightly CI matrix against latest upstream scaffolders).

The Docker dev stack

--docker writes two compose files. compose.yaml builds the per-app production images — the same ones the deploy workflow ships. compose.dev.yaml runs each app's dev server instead, all from one shared dev.Dockerfile, so you can bring the whole stack up in containers while you work:

bun run docker:dev     # docker compose -f compose.dev.yaml up --watch
bun run docker:prod    # docker compose up --build

The --watch is load-bearing. There are no bind mounts — Compose Watch syncs your edits into the running containers, and rebuilds when a package.json or bun.lock changes (a new dependency can't be synced into an image whose node_modules is already baked in). Bind mounts don't reliably deliver file-change events from Windows or macOS hosts, which is exactly where hot reload silently stops working. Plain up (no --watch) boots the same stack with the source frozen at image-build time.

Each framework's dev server is started so it binds 0.0.0.0 and is reachable through the published port (-H 0.0.0.0 for Next, --host 0.0.0.0 for Vite and Nuxt, FASTIFY_ADDRESS for Fastify; Nest, Express, and Hono already do). Expo is not in either stack — Metro needs LAN reachability and QR pairing, so bun run dev:mobile on the host stays the path.

Flags

Flag Meaning
--web <next|react-vite|nuxt|none> Web frontend
--mobile <expo|none> Mobile app
--api <nest|express|hono|fastify|none> API backend
--docker / --no-docker Dockerfiles + compose.yaml
--cicd / --no-cicd GitHub Actions CI + VPS deploy pipeline (implies docker)
--agents <claude,cursor,copilot,codex,gemini,windsurf|none> Format-on-edit hooks for AI coding agents (see below)
--skills <stack,web-design,frontend-design|none> Best-practice skills for those agents (see below)
--json Agent mode: no prompts, stdout is exactly one JSON manifest
-y, --yes Defaults: next + nest + docker + cicd + claude hooks + stack skills
--dry-run Print the manifest without writing anything
--no-git, --no-install, --force, --verbose, --keep-on-error What they say

Agent mode

--json makes the CLI a good citizen for AI coding agents: all progress goes to stderr, stdout carries a single JSON manifest (apps, ports, scripts, required deploy secrets, next steps), exit codes are meaningful (0 ok / 1 pipeline / 2 usage), and the generated repo contains an AGENTS.md so agents don't re-derive conventions. Boilerplate comes from official scaffolders, not from model output — that's the whole point.

Format-on-edit hooks for AI agents

An agent that edits a file rarely formats it. --agents fixes that at the source: every file the agent touches is run through oxlint --fix + oxfmt the moment the edit lands, using the exact rules lint-staged applies at commit — so by the time you look at the diff, it is already clean.

One shared script does the work (scripts/agent-format.ts, run by bun, no extra dependencies), and each agent gets a two-line config pointing at it:

Agent Config written Fires on
Claude Code (recommended) .claude/settings.json PostToolUse for Edit / Write
Cursor .cursor/hooks.json afterFileEdit
GitHub Copilot (CLI + agent) .github/hooks/format.json postToolUse for edit / create
OpenAI Codex .codex/hooks.json PostToolUse for apply_patch
Gemini CLI .gemini/settings.json AfterTool for write / replace
Windsurf .windsurf/hooks.json post_write_code

Pick several (--agents claude,cursor) if your team is mixed — the configs are independent and all commit cleanly. The script also works by hand: bun scripts/agent-format.ts path/to/file.ts.

Interactive runs preselect Claude Code; --yes picks it; --json writes none unless you ask (agents shouldn't get hooks they didn't request). In interactive mode Esc goes back one question (your earlier answer is preselected) and Ctrl+C quits.

Best-practice skills for AI agents

A hook keeps agent output formatted; a skill keeps it idiomatic. --skills installs Agent Skills — SKILL.md playbooks an agent loads on demand — for the agents you chose, using the same rule as the apps: nothing is vendored here, the skills CLI fetches each one from its maintainer's repo at scaffold time, so you get what they ship today.

Why bother: agents otherwise write React, Nest or Fastify from whatever their training data remembers. A skill puts the framework's current conventions and pitfalls one file away — Next.js measures a clear gain when agents read bundled docs instead of guessing, and the per-framework skills below are the same idea for the rest of the stack. The generated AGENTS.md tells the agent which skill to load before touching which app.

Pack Installs
stack (default) One set per selected framework: Next.js / React + Vite → Vercel's vercel-react-best-practices (+ vercel-composition-patterns for Vite) · Nuxt → nuxt + vue (antfu) · Expo → expo-router, expo-project-structure, expo-native-ui, expo-data-fetching (Expo) · Hono → hono (Hono) · Fastify → fastify-best-practices (Matteo Collina) · Express → node (Matteo Collina) · NestJS → nestjs-best-practices (community; no first-party one exists yet)
web-design Vercel's web-design-guidelines: 100+ accessibility/UX audit rules — "review my UI" gets a real checklist
frontend-design Anthropic's frontend-design: opinionated visual direction for new UI instead of template defaults

Where they land follows each agent's discovery rules: Cursor, Codex, Copilot and Gemini read the shared .agents/skills/; Claude Code reads .claude/skills/ and Windsurf .windsurf/skills/, so those get a copy (real copies, not symlinks — symlinks need Developer Mode on Windows and the skills CLI silently writes nothing without it). skills-lock.json pins sources and hashes; bunx skills update refreshes. Skill directories are excluded from oxlint/oxfmt/knip so third-party content never breaks bun run check.

A skill that cannot be fetched — repo renamed, offline — does not fail the run: it is reported in the manifest (agentSkills.failed) and in a warning, and AGENTS.md lists only what was installed. --skills needs at least one agent; --yes picks stack, --json installs none unless asked.

Requirements

Bun ≥ 1.3 on PATH, plus git (unless --no-git). The CLI itself runs under Node ≥ 20, so npx create-bunship works too.

Your chosen stack may need more, because framework CLIs (nuxt, next, vite, nest) run under node via their bin shebang rather than under bun — so the node on your PATH is what actually builds the generated repo:

Stack Needs
Nuxt Node ≥ 22.19
React + Vite Node ≥ 20.19
Next.js Node ≥ 20.9
NestJS Node ≥ 20

bunship checks this during preflight and fails in about a second with the version it found, rather than letting you discover it as an upstream stack trace after a full install.

Related Packages

create-nuxion

Scaffold the Nuxion NestJS + Nuxt/Next monorepo (Bun + Turbo) — bun create nuxio...

233 1
@duxweb/dvha-template

Create DVHA project from template

6,499
@chamathdilshanc/create-stack

The Ultimate Multi-Tiered Project Orchestrator — an interactive CLI that scaffol...

5,058 0
routeman-cli

Generate a complete Postman collection from your Node.js, Bun or Deno API (Expre...

370 0
create-prism-app

Scaffold a production-grade, opinionated full-stack starter in seconds — Vue, Nu...

970 0

Version History

Version Released License
0.6.0 MIT
0.5.0 MIT
0.4.0 MIT
0.3.0 MIT
0.2.2 MIT