We've been building Crust (https://crustjs.com/), a TypeScript-first, Bun-native CLI framework with zero dependencies. It's been powering our core product internally for a while, and we're now open-sourcing it.
The problem we kept running into: existing CLI frameworks in the JS ecosystem are either minimal arg parsers where you wire everything yourself, or heavyweight frameworks with large dependency trees and Node-era assumptions. We wanted something in between.
What Crust does differently:
- Full type inference from definitions — args and flags are inferred automatically. No manual type annotations, no generics to wrangle. You define a flag as type: "string" and it flows through to your handler.
- Compile-time validation — catches flag alias collisions and variadic arg mistakes before your code runs, not at runtime.
- Zero runtime dependencies — @crustjs/core is ~3.6kB gzipped (21kB install). For comparison: yargs is 509kB, oclif is 411kB.
- Composable modules — core, plugins, prompts, styling, validation, and build tooling are all separate packages. Install only what you need.
- Plugin system — middleware-based with lifecycle hooks (preRun/postRun). Official plugins for help, version, and shell autocompletion.
- Built for Bun — no Node compatibility layers, no legacy baggage.
Quick example:
import { Crust } from "@crustjs/core";
import { helpPlugin, versionPlugin } from "@crustjs/plugins";
const main = new Crust("greet")
.args([{ name: "name", type: "string", default: "world" }])
.flags({ shout: { type: "boolean", short: "s" } })
.use(helpPlugin())
.use(versionPlugin("1.0.0"))
.run(({ args, flags }) => {
const msg = `Hello, ${args.name}!`;
console.log(flags.shout ? msg.toUpperCase() : msg);
});
await main.execute();
Scaffold a new project: bun create crust my-cli
Site: https://crustjs.com
GitHub: https://github.com/chenxin-yan/crustHappy to answer any questions about the design decisions or internals.
I was looking for something like this.
Does the help plugin not support color?
Looks like the spacing is messed up too. I just converted my app to use it and its coming out like
``` COMMANDS: export-schemaExport table definitions from existing database to YAML export-dataExport table data in CSV format import-dataImport table data from CSV file schema-sqlConvert YAML schema back to MySQL export-usersExport users in YAML format users-sql Convert users.yaml back into SQL export-allExport all data from host export-all-tgzExport all data from host databases-sqlConvert databases.yaml back into SQL export-typescriptExport TypeScript interfaces ```
i.e. there's no space after `export-schema` it just goes immediately to the description.
This looks useful. But, it's interesting how the backend-world and front-end world keep diverging. I must admit, I had no idea what this was from the title. "CLI framework"? But in backend-land, these would typically be called "argument parsers" or "command line argument parsers". But maybe I am missing some of the functionality.
Looks cool. If anyone is interested in a simple option with autocomplete working out of the box and no extra bells and whistles, feel free to check out my project: https://github.com/gutenye/script.js
also: no "C", and no "rust", despite being a portmanteau of both these other languages names :)
this is cool! i'd recommend fleshing out the README. Clicked on the link before the discussion and was a tad confused.
Any plans to support Node.js? Also some comparison (at least design choices) with existing frameworks would be nice.
Is there an examples section? Would be helpful to see a demo
nice, congrats on launch. To get an idea... what's the size of a standalone hello world cli binary?
I’ve been using the jsr:@cliffy/* packages from deno to solve the same problem.
> Versions before 1.0 do not strictly follow semantic versioning.
Sorry for being nitpicky, but yes they do. Semantic versioning[0] allows arbitrary changes while the major version is 0:
> Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.
[0]: https://semver.org/
wow, cannot wait to start with this
[dead]
[dead]
Psst, the GitHub link in your post is broken (it should be https://github.com/chenxin-yan/crust).
seems pretty useful and easy to setup