func is a TypeScript framework for building modern, extensible command-line applications. It uses classes and decorators to declare commands and provides input definition and validation, command dispatch, error boundaries, service injection, and a range of type-safety features.
It is an efficient end-to-end solution for the entire workflow from local development to production builds.
This is not another command-line argument parser. func is designed to solve architectural problems in command-line applications. By providing a complete project model, ecosystem components, a consistent input and runtime model, and an integrated build workflow,
it helps projects stay healthy and extensible as they grow.
func also cares about final bundle size and performance. Automatic tree shaking, precompilation, and decoupled packages help applications stay lean and efficient,
combining sound architecture with compact output. Whether you are validating a prototype, starting an MVP, or building a large project, you can adopt it without unnecessary overhead.
Why?
The complexity of a CLI project usually rises quickly. Even a modest extension can make the code difficult to understand and maintain, leaving the project trapped in endless patches and redundant defensive programming. A single input may need a name, type, default, validation rules, and an error message; commands may need to share filesystem access, network requests, and common business rules; after release, the application must work across platforms while preserving existing invocation patterns.
If all these responsibilities are packed into argument parsing and command callbacks, changing even one option affects parsing, validation, execution, and error handling at the same time. As features accumulate, every modification requires understanding and verifying an ever-larger portion of the codebase.
func provides ready-made capabilities for common CLI requirements and gives their Handlers strict TypeScript contracts. Projects can therefore support larger and more complex business modules without eroding their structure.
Each change can stay focused on business logic instead of reaching into framework internals; developers do not need to understand the machinery underneath.
Overall considerations
In the current benchmark workload (the sample project used by benchmarks), func has a mean cold start of 37.9 ms and a raw artifact size of 18.7 KiB. Its startup performance is on par with Commander and cac, while its artifact is substantially smaller than those produced by yargs and oclif—placing it in the top tier for both performance and size. In the same report’s proxy evaluation of developer experience and maintainability, func scores 95 and 90 respectively, the highest scores in this comparison.
| Category | Performance | Score |
|---|---|---|
Performance | func registers every command in advance through reflection, keeping execution static and complexity low. | ✅ |
Architecture | Provides starter templates and a scalable architecture with room for continued growth. | ✅ |
Developer experience | Complete type support and editor assistance, backed by thoughtful project architecture and scaffolding. | ✅ |
The following examples implement the same input rules. func keeps types, defaults, and validation on the fields they describe, and the handler receives input only after it has been converted and validated.
Comparing the same command
The same input rules implement the artifact inspect command: a required reference, a platform enum, a numeric retry count, and a JSON flag. Line counts exclude imports and shared business functions.
const artifact = program
.command('artifact')
.description('inspect an artifact')
artifact
.command('inspect')
.requiredOption('--reference <image>')
.addOption(
new Option('--platform <platform>')
.choices(platforms)
.default('linux/amd64'),
)
.option(
'--retries <count>',
'download retries',
value => {
const retries = Number(value)
if (Number.isNaN(retries)) {
throw new InvalidArgumentError(
'retries must be a number',
)
}
return retries
},
2,
)
.option('--json')
.action(options => {
if (!isDigestReference(options.reference)) {
throw new Error(
'reference must include a sha256 digest',
)
}
inspectArtifact(options.reference, options)
})@Command('artifact')
class ArtifactCommand {
@Required()
@ValueValidate(isDigestReference)
@Value()
reference?: string
@Enum(platforms)
@Value()
platform: string = 'linux/amd64'
@Value()
retries: number = 2
@Flag()
json = false
@Handler('inspect')
inspect(): void {
inspectArtifact(this.reference!, this)
}
}Lines of code are not a criterion for evaluating a framework. This comparison simply shows that func remains fast and lightweight while using clearer, more modern, and developer-friendly engineering practices, keeping projects healthy
and easy for people to understand, extend, and maintain at a glance.
Agent compatibility
Beyond the qualities above, func also provides excellent Agent compatibility.
Type safety is central to func. Clear, rigorous interfaces define firm boundaries between commands, input, validation, handlers, and services.
This allows an Agent to follow project rules and generate safe, reliable, stable, and architecturally sound code. When necessary, you may not need to write any code yourself—guiding the business logic can be enough to produce a high-quality terminal tool.
At the same time, func provides complete testing support and Agent compatibility. An Agent can run commands from a user’s perspective, verify exit behavior and stable output, and add automated acceptance tests for expected behavior,
further safeguarding business logic and project quality through automation.
Open the Agent guide. Choose a task that fits the project’s current stage, then let an Agent create the project, improve its structure, or add CLI behavior tests.
Where to start next
Choose a documentation entry based on your current goal:
- Using func for the first time: create a project and run your first command.
- Understanding the func runtime model: understand how commands, handlers, input, and services relate.
- Looking for a specific capability: browse Commands, Field Options, Parameters, or Error Handling.