Getting Started
Get up and running with Navios Commander in minutes. This guide will walk you through installation, basic setup, and your first CLI command.
What is Navios Commander?
Navios Commander is a framework for building type-safe CLI applications with TypeScript. It provides:
- Type-safe commands with Zod schema validation
- Dependency injection for clean, testable code
- Modular organization with CLI modules
- Automatic help generation from command metadata
Commands are defined as classes with decorators, making them easy to organize, test, and extend.
Installation
Install Navios Commander using your preferred package manager:
npm install @navios/commander zod
# or
yarn add @navios/commander zod
# or
pnpm add @navios/commander zod
zod is a peer dependency required for schema validation. @navios/core (which includes DI) is bundled with @navios/commander.
Prerequisites
- Node.js: 18 or higher
- TypeScript: 4.5 or higher
- Modern TypeScript project: ES2022+ target recommended
TypeScript Configuration
Make sure your tsconfig.json has the correct settings for decorators:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "node16",
"experimentalDecorators": false
}
}
Navios Commander uses native ES decorators, not legacy decorators. Ensure experimentalDecorators is set to false (or omitted).
Your First Command
Commands are classes decorated with @Command that implement the CommandHandler interface. They're organized into modules and executed by the CommanderFactory.
Here's a complete example:
import { Command, CommandHandler, CliModule, CommanderFactory } from '@navios/commander'
import { z } from 'zod'
// 1. Define command options schema
const greetOptionsSchema = z.object({
name: z.string(),
greeting: z.string().optional().default('Hello'),
})
type GreetOptions = z.infer<typeof greetOptionsSchema>
// 2. Create a command
@Command({
path: 'greet',
optionsSchema: greetOptionsSchema,
})
export class GreetCommand implements CommandHandler<GreetOptions> {
async execute(options: GreetOptions) {
console.log(`${options.greeting}, ${options.name}!`)
}
}
// 3. Create a CLI module
@CliModule({
commands: [GreetCommand],
})
export class AppModule {}
// 4. Bootstrap and run
async function bootstrap() {
const app = await CommanderFactory.create(AppModule)
await app.init()
const adapter = app.getAdapter()
await adapter.run(process.argv)
await app.close()
}
bootstrap()
How It Works
-
Command Definition: The
@Commanddecorator registers the command with a path and optional schema for validation. -
Module Organization: Commands are organized into modules using
@CliModule. Modules can import other modules to build complex CLI structures. -
Execution:
CommanderFactorycreates the application, initializes modules, and executes commands based on command-line arguments. -
Type Safety: Zod schemas provide runtime validation and TypeScript type inference for command options.
Running Your CLI
Build your TypeScript code and run it:
npm run build
node dist/cli.js greet --name World --greeting Hi
# Output: Hi, World!
The framework automatically generates help text:
node dist/cli.js help
# or
node dist/cli.js --help
Using Dependency Injection
Commands can use dependency injection to access services. Simply inject services using the inject() function:
import { inject, Injectable } from '@navios/di'
@Injectable()
class UserService {
async getUser(id: string) {
return { id, name: 'John Doe', email: '[email protected]' }
}
}
@Command({ path: 'user:show', optionsSchema: userOptionsSchema })
export class ShowUserCommand implements CommandHandler<{ userId: string }> {
private userService = inject(UserService)
async execute(options: { userId: string }) {
const user = await this.userService.getUser(options.userId)
console.log(`User: ${user.name} (ID: ${user.id})`)
}
}
Learn more about dependency injection in commands.
Next Steps
Now that you have the basics down, explore these topics:
- Commands - Learn how to create and structure commands
- Modules - Organize commands into modules
- Dependency Injection - Use DI in your commands
- Validation - Validate command options with Zod
- Execution Context - Access command execution information
- Testing - Test your commands
Troubleshooting
Command Not Found
Problem: Getting "Command not found" error.
Solution:
- Make sure the command is registered in a module
- Verify the module is imported in your root module
- Check that
app.init()was called beforeadapter.run()
Options Not Validated
Problem: Options are not being validated.
Solution:
- Ensure you provided an
optionsSchemain the@Commanddecorator - Verify the schema is a valid Zod schema
- Check that options match the schema structure
Services Not Injected
Problem: Injected services are undefined or not working.
Solution:
- Make sure services are decorated with
@Injectable() - Verify services are imported before use
- Check that the DI container is properly initialized
Type Errors
Problem: TypeScript type errors with command options.
Solution:
- Use
z.infer<typeof schema>to get the correct type - Ensure the
CommandHandlerinterface uses the correct type parameter - Check that all dependencies are properly typed
Getting Help
- Check the API Reference for complete method signatures
- Review the Recipes for common patterns
- See the Best Practices for guidance
- Visit the GitHub repository for issues and discussions