Project Setup
# Create a CLI app:
dart create --template=console my_cli
# Structure:
# my_cli/
# bin/my_cli.dart ← entry point
# lib/ ← library code
# pubspec.yaml
Command-line Arguments
// bin/my_cli.dart
import 'dart:io';
void main(List<String> args) {
if (args.isEmpty) {
print('Usage: my_cli <command> [options]');
exit(1);
}
switch (args[0]) {
case 'hello':
var name = args.length > 1 ? args[1] : 'World';
print('Hello, $name!');
case 'add':
if (args.length < 3) {
stderr.writeln('Usage: add <num1> <num2>');
exit(1);
}
var a = double.parse(args[1]);
var b = double.parse(args[2]);
print('$${args[1]} + $${args[2]} = $${a + b}');
default:
stderr.writeln('Unknown command: $${args[0]}');
exit(1);
}
}
// Or use the 'args' package for structured parsing:
// dart pub add args
Reading stdin
import 'dart:io';
void main() {
stdout.write('Enter your name: ');
var name = stdin.readLineSync();
stdout.write('Enter your age: ');
var ageStr = stdin.readLineSync() ?? '0';
var age = int.tryParse(ageStr) ?? 0;
print('Hello, $name! You are $age years old.');
// Read multiple lines until EOF:
print('Enter text (Ctrl+D to finish):');
String? line;
var lines = <String>[];
while ((line = stdin.readLineSync()) != null) {
lines.add(line!);
}
print('You entered $${lines.length} lines');
}
Colored Output
// ANSI color codes for terminal output
class Colors {
static const reset = '\x1B[0m';
static const red = '\x1B[31m';
static const green = '\x1B[32m';
static const yellow = '\x1B[33m';
static const blue = '\x1B[34m';
static const bold = '\x1B[1m';
static String colorize(String text, String color) => '$color$text$reset';
static String error(String text) => colorize('[ERROR] $text', red);
static String success(String text) => colorize('[OK] $text', green);
static String warning(String text) => colorize('[WARN] $text', yellow);
static String info(String text) => colorize('[INFO] $text', blue);
}
void main() {
print(Colors.success('Server started'));
print(Colors.warning('Low disk space'));
print(Colors.error('Connection refused'));
print(Colors.info('Processing 100 items'));
}
CLI App Example: Task Manager
import 'dart:io';
import 'dart:convert';
class TaskManager {
final String _file = 'tasks.json';
List<Map<String, dynamic>> _tasks = [];
void load() {
var f = File(_file);
if (f.existsSync()) {
_tasks = List.from(jsonDecode(f.readAsStringSync()));
}
}
void save() => File(_file).writeAsStringSync(jsonEncode(_tasks));
void add(String title) {
_tasks.add({'id': DateTime.now().millisecondsSinceEpoch, 'title': title, 'done': false});
save();
print('Added: $title');
}
void list() {
if (_tasks.isEmpty) { print('No tasks'); return; }
for (var t in _tasks) {
print('[$${t['done'] ? 'x' : ' '}] $${t['id']}: $${t['title']}');
}
}
void complete(int id) {
var task = _tasks.firstWhere((t) => t['id'] == id, orElse: () => {});
if (task.isEmpty) { print('Task not found'); return; }
task['done'] = true;
save();
print('Completed: $${task['title']}');
}
}
void main(List<String> args) {
var manager = TaskManager()..load();
switch (args.isEmpty ? 'list' : args[0]) {
case 'add':
manager.add(args.skip(1).join(' '));
case 'done':
manager.complete(int.parse(args[1]));
default:
manager.list();
}
}
🧠 Quiz
1. How do you write to stderr in Dart CLI?
- A) print()
- B) console.error()
- C) stderr.writeln() ✅
- D) System.err.println()
2. What does exit(1) signify in a CLI app?
- A) The app ran successfully
- B) The app exited with an error (non-zero code) ✅
- C) Dart-specific success code
- D) Restart the app
Summary
Dart CLI apps start with void main(List<String> args). Read stdin with stdin.readLineSync(), write to stdout/stderr, and exit with exit(code). Use the args package for complex argument parsing. Use ANSI codes for colored terminal output. Dart CLI apps compile to native binaries with dart compile exe.