Built for Bun
The Minimal CLI Framework for Bun
Type-safe, fast, and delightfully simple. Build production-ready CLIs with zero configuration and full TypeScript support.
greet.ts
import { defineCommand, option } from '@bunli/core'import { z } from 'zod'export default defineCommand({ name: 'greet', description: 'Greet someone', options: { name: option( z.string().min(1), { description: 'Name to greet', short: 'n' } ), excited: option( z.coerce.boolean().default(false), { description: 'Add excitement', short: 'e' } ) }, handler: async ({ flags }) => { const greeting = `Hello, ${flags.name}${flags.excited ? '!' : '.'}` console.log(greeting) }})Terminal
$ greet --name World --excited Hello, World!
✨ Full TypeScript support with automatic type inference
Everything You Need
Simple, powerful, and ready for production
Blazing Fast
Powered by Bun's native speed
Type-Safe
Full TypeScript autocompletion
Zero Config
Works out of the box, sensible defaults
Minimal API
Learn once, use everywhere
Testing Built-in
First-class testing utilities included
Easy Deploy
Compile to single executable
See the Difference
Less boilerplate, more productivity
bunli-cli.ts
// Clean and type-safeimport { defineCommand, option } from '@bunli/core'import { z } from 'zod'export default defineCommand({ name: 'serve', description: 'Start the server', options: { port: option( z.coerce.number().default(5000), { description: 'Port to bind', short: 'p' } ), verbose: option( z.coerce.boolean().default(false), { description: 'Run with verbose logging', short: 'v' } ) }, handler: ({ flags }) => { // flags.port is number // flags.verbose is boolean console.log(`Server on ${flags.port}`) }})80%
Less boilerplate
100%
Type safe
10x
Faster development
Powerful Features, Simple API
Everything you need to build production-ready CLIs
Schema Validation
import { defineCommand, option } from '@bunli/core'import { z } from 'zod'export default defineCommand({ name: 'deploy', description: 'Deploy to environment', options: { env: option( z.enum(['dev', 'staging', 'prod']), { description: 'Target environment' } ), port: option( z.coerce.number().min(1000).max(9999), { description: 'Port number (1000-9999)' } ), force: option( z.coerce.boolean().default(false), { description: 'Force deployment', short: 'f' } ) }, handler: ({ flags }) => { // TypeScript knows: // flags.env is 'dev' | 'staging' | 'prod' // flags.port is number (1000-9999) // flags.force is boolean console.log(`Deploying to ${flags.env}:${flags.port}`) }})