Appendix U: Camel CLI Deep Dive
A comprehensive guide to the Camel CLI — prototyping routes with camel run, tracing exchanges, debugging, managing infrastructure, and exporting to production runtimes.
Every YAML DSL example in this tutorial uses a single command to run: camel run *.yaml. That command is the entry point to the Camel CLI — a tool that serves two distinct roles. First, it is a prototyping runtime: write a YAML route file, run it, and you have a live integration in seconds with no Maven project, no pom.xml, no build step. Second, it is a management tool: inspect running Camel applications, trace live exchanges, check health, and monitor Kafka consumer lag — regardless of whether the application was started from the CLI or deployed as a Quarkus or Spring Boot service.
This appendix covers both roles in depth. By the end you will know how to prototype a route, debug it interactively, and export it into a production-ready Maven project — the complete lifecycle from idea to deployment.
The code is in examples/39-camel-cli/.
camel run *.yaml
Installation
The Camel CLI is distributed through JBang, a tool that runs Java programs without requiring a project setup. Install JBang first, then install the Camel CLI as a JBang application:
# Install JBang (if not already installed)
curl -Ls https://sh.jbang.dev | bash -s - app setup
# Install the Camel CLI
jbang app install camel@apache/camel
Verify the installation:
camel version
Apache Camel CLI 4.20.0
The CLI ships as a single binary that delegates to JBang under the hood. When you run camel run, JBang resolves Camel dependencies, downloads them once, caches them locally, and starts the Camel runtime — no Maven, Gradle, or IDE required.
Upgrading
To upgrade the CLI after a new Camel release:
jbang app install --force camel@apache/camel
This pulls the latest version from the Apache Camel GitHub repository and replaces the cached binary. Verify with camel version to confirm the upgrade.
Running routes
The camel run command is the workhorse. Point it at one or more YAML, Java, or XML route files and it starts a Camel runtime with those routes loaded:
# Run a single route file
camel run order-router.yaml
# Run all YAML files in the current directory
camel run *.yaml
# Run with dev mode — live reload on file changes
camel run --dev *.yaml
How dependency resolution works
When the CLI parses your route file, it detects which Camel components you reference — kafka:, redis-lettuce:, rest:, json marshalling — and resolves the corresponding Maven artifacts automatically. You never declare dependencies in a pom.xml. The CLI’s dependency resolver handles:
| Component reference | Resolved artifact |
|---|---|
kafka:eip.orders.express |
camel-kafka |
redis-lettuce:localhost:6379 |
camel-redis-lettuce |
rest: configuration |
camel-rest, camel-platform-http |
json marshal/unmarshal |
camel-jackson |
This is the key advantage for prototyping. Add a to: "slack:#alerts" step to your route, and the CLI downloads camel-slack without any configuration change.
The example routes
The example directory contains two routes that demonstrate a content-based router and an enricher — two patterns covered in Chapters 9 and 10 — wired together through Kafka.
order-router.yaml — A REST API that accepts POST requests on /api/orders and routes each order to a Kafka topic based on the orderType header:
# REST API that accepts order submissions and routes each order
# to a Kafka topic determined by its orderType header —
# EXPRESS, STANDARD, or BULK.
- rest:
path: /api/orders
post:
- to: "direct:route-order"
- consumes: application/json
produces: application/json
- route:
id: route-order
from:
uri: "direct:route-order"
steps:
- unmarshal:
json:
library: Jackson
- log: "Order received: ${body[orderId]} — type: ${header.orderType}"
- choice:
when:
- simple: "${header.orderType} == 'EXPRESS'"
steps:
- log: "EXPRESS order ${body[orderId]} → express topic"
- to:
uri: "kafka:eip.orders.express"
parameters:
brokers: ""
- simple: "${header.orderType} == 'BULK'"
steps:
- log: "BULK order ${body[orderId]} → bulk topic"
- to:
uri: "kafka:eip.orders.bulk"
parameters:
brokers: ""
otherwise:
steps:
- log: "STANDARD order ${body[orderId]} → standard topic"
- to:
uri: "kafka:eip.orders.standard"
parameters:
brokers: ""
order-enricher.yaml — Consumes express orders from Kafka, looks up customer data in Redis, and publishes the enriched order downstream:
# Consumes express orders from Kafka, enriches each order with
# customer data retrieved from Redis, and publishes the enriched
# order to a downstream topic.
- route:
id: order-enricher
from:
uri: "kafka:eip.orders.express"
parameters:
brokers: ""
groupId: ""
steps:
- unmarshal:
json:
library: Jackson
- log: "Enriching express order ${body[orderId]} for customer ${body[customerId]}"
- setHeader:
name: RedisKey
simple: "customer:${body[customerId]}"
- toD:
uri: "redis-lettuce::?command=GET&key=${header.RedisKey}"
- setHeader:
name: customerName
jsonpath: "$.name"
- setHeader:
name: customerTier
jsonpath: "$.tier"
- log: "Enriched order ${body[orderId]} — customer: ${header.customerName}, tier: ${header.customerTier}"
- marshal:
json:
library: Jackson
- to:
uri: "kafka:eip.orders.enriched"
parameters:
brokers: ""
Configuration
Properties go in application.properties in the same directory. The CLI loads this file automatically:
# Kafka
camel.component.kafka.brokers=localhost:9092
camel.component.kafka.group-id=eip-cli-demo
# Redis
camel.component.redis-lettuce.host=localhost
camel.component.redis-lettuce.port=6379
# REST
camel.rest.port=8088
camel.rest.binding-mode=json
Dev mode
The --dev flag enables live reload. When you save a change to any route file or application.properties, the CLI detects the modification, stops the running routes, reloads the files, and restarts — all within a second or two:
camel run --dev *.yaml
Dev mode also enables the developer console (covered next) and makes camel trace output more detailed. It is the recommended way to run during development.
You can also use the camel dev alias, which is equivalent to camel run --dev:
camel dev *.yaml
OpenAPI generation
If your route defines a REST DSL configuration, the CLI can generate an OpenAPI specification:
camel run --open-api order-router.yaml
This starts the route and serves the generated OpenAPI document at http://localhost:8088/api-docs. Useful for sharing an API contract with frontend teams while the route is still a prototype.
Developer console
When running in dev mode, the CLI starts a developer console on port 8080. Open http://localhost:8080/q/dev in a browser to see:
| Section | What it shows |
|---|---|
| Routes | All loaded routes with their status (Started, Stopped), uptime, and exchange counters |
| Endpoints | Every endpoint URI in use — Kafka topics, REST paths, Redis connections — with message counts |
| Health | Readiness and liveness checks — Kafka broker connectivity, Redis connection pool status |
| Statistics | Per-route performance: total exchanges, failed exchanges, mean processing time, last processing time |
| Properties | Resolved configuration properties and their sources |
The console refreshes automatically. It is a lightweight alternative to connecting JMX or an observability stack when you just need a quick status check during prototyping.
The console URL follows the Quarkus convention (/q/dev) because the Camel CLI uses Quarkus as its underlying runtime. This also means that Quarkus Dev UI extensions work with CLI-launched routes.
Tracing and debugging
Tracing exchanges
The camel trace command attaches to a running Camel integration and displays exchanges flowing through routes in real time. Open a second terminal while your routes are running:
camel trace
Output is a live-updating table:
PID NAME ROUTE NODE ELAPSED STATUS BODY
1234 order-router route-order unmarshal1 2ms ✔ {"orderId":"ORD-9001","item":"Wi...
1234 order-router route-order log1 0ms ✔ {"orderId":"ORD-9001","item":"Wi...
1234 order-router route-order choice1 1ms ✔ {"orderId":"ORD-9001","item":"Wi...
1234 order-router route-order toKafkaExpress 15ms ✔ {"orderId":"ORD-9001","item":"Wi...
1234 order-enricher order-enricher unmarshal2 1ms ✔ {"orderId":"ORD-9001","customerId...
1234 order-enricher order-enricher toRedis1 8ms ✔ {"name":"Acme Corp","tier":"GOLD"}
1234 order-enricher order-enricher toKafkaEnriched 12ms ✔ {"orderId":"ORD-9001","customerNa...
Each row is a processing step. The ELAPSED column shows how long that step took, making it easy to spot slow processors — a Kafka produce that takes 200ms, a Redis lookup timing out, or a marshalling step that is unexpectedly expensive.
Filtering traces
You can filter traces to a specific route:
# Trace only the enricher route
camel trace --filter=order-enricher
Or limit to failed exchanges:
camel trace --filter=fail
Debugging with breakpoints
The camel debug command provides step-by-step debugging. Set a breakpoint on a route node and the CLI pauses execution when an exchange reaches that point:
camel debug
Once attached, the debugger shows an interactive prompt:
camel debug> breakpoint route-order choice1
Breakpoint set on route-order/choice1
camel debug> resume
Waiting for exchange...
Exchange hit breakpoint at route-order/choice1
Exchange ID: 1A2B3C4D-5E6F
Body: {"orderId":"ORD-9001","item":"Wireless Headphones","quantity":2}
Headers:
orderType = EXPRESS
Content-Type = application/json
camel debug> step
Stepped to: toKafkaExpress
Body: {"orderId":"ORD-9001","item":"Wireless Headphones","quantity":2}
camel debug> continue
Debugging is particularly useful when a content-based router is not matching the branch you expect — you can inspect the exact header values and body content at the decision point.
Inspecting running integrations
The CLI includes a set of camel get and camel ps commands for inspecting running Camel applications. These commands work against any Camel application that has the camel-management component enabled — not just CLI-launched routes. This means you can use them to inspect Quarkus and Spring Boot applications too.
Listing running integrations
camel ps
PID NAME CAMEL RUNTIME UPTIME ROUTES STATUS
1234 order-router 4.20.0 cli 12m 30s 2 Running
5678 shipping-svc 4.20.0 quarkus 2h 15m 8 Running
Route status
camel get routes
PID ROUTE STATUS UPTIME TOTAL FAILED INFLIGHT MEAN LAST
1234 route-order Started 12m 30s 47 0 0 18ms 12ms
1234 order-enricher Started 12m 30s 15 1 0 32ms 28ms
The TOTAL, FAILED, and INFLIGHT columns give you a quick operational picture. A rising FAILED count or a non-zero INFLIGHT with increasing MEAN time signals trouble.
Health checks
camel get health
PID CHECK STATUS MESSAGE
1234 camel/context UP CamelContext is started
1234 camel/routes UP 2/2 routes started
1234 kafka/eip.orders.* UP Connected to localhost:9092
1234 redis UP Connected to localhost:6379
Health checks are the CLI’s equivalent of the /q/health endpoint in Quarkus. They verify that every external dependency — Kafka brokers, Redis, databases — is reachable.
Kafka consumer lag
camel get kafka
PID TOPIC PARTITION OFFSET LAG CONSUMER-GROUP
1234 eip.orders.express 0 142 3 eip-cli-demo
1234 eip.orders.standard 0 89 0 eip-cli-demo
1234 eip.orders.bulk 0 23 0 eip-cli-demo
A LAG value greater than zero means the consumer is falling behind the producer. This is the same information you would get from kafka-consumer-groups.sh --describe, but scoped to the routes in your integration and available without connecting to the Kafka broker directly.
Endpoint statistics
camel get endpoint
PID URI DIRECTION TOTAL FAILED LAST
1234 kafka:eip.orders.express InOut 47 0 12ms ago
1234 kafka:eip.orders.standard Out 32 0 45s ago
1234 kafka:eip.orders.bulk Out 15 0 2m ago
1234 redis-lettuce:localhost:6379 InOut 15 1 28ms ago
1234 kafka:eip.orders.enriched Out 14 0 28ms ago
Infrastructure services
The CLI can spin up infrastructure containers for local development using Testcontainers. This is useful when you want to prototype a route without running the full Podman stack from scripts/setup-stack.sh.
Listing available services
camel infra list
SERVICE IMAGE PORT
kafka apache/kafka:latest 9092
redis redis:7 6379
postgres postgres:17 5432
activemq apache/activemq-artemis:latest 61616
mongodb mongo:7 27017
minio minio/minio:latest 9000
elasticsearch elastic/elasticsearch:8.17.0 9200
rabbitmq rabbitmq:4-management 5672
Starting a service
# Start a Kafka container
camel infra run kafka
The CLI pulls the container image (if not cached), starts it, and configures the Camel Kafka component to connect to it automatically. No application.properties change needed — the CLI injects the broker address.
You can start multiple services:
camel infra run kafka redis
This is the fastest path from zero to a working prototype. Write a route, run camel infra run kafka, and camel run --dev *.yaml — three commands to a live integration with real infrastructure.
How it relates to the Podman stack
The camel infra containers are ephemeral — data is lost when you stop them. For persistent development environments, use the Podman stack (./scripts/setup-stack.sh) described in Chapter 0. The CLI containers are best for quick experiments and throwaway prototypes.
Interactive shell
The camel shell command opens an interactive REPL with tab completion and command history:
camel shell
Apache Camel CLI (shell)
Type 'help' for available commands.
camel> run order-router.yaml
Started route: route-order
camel> get routes
ROUTE STATUS UPTIME TOTAL FAILED
route-order Started 10s 0 0
camel> trace
Waiting for exchanges...
Tab completion
The shell supports tab completion for commands, sub-commands, and file names:
camel> get <TAB>
routes health kafka endpoint context
camel> run ord<TAB>
order-router.yaml order-enricher.yaml
Watch mode
Within the shell, you can prefix any get command with --watch to refresh the output periodically:
camel> get routes --watch
This turns the terminal into a live dashboard — route statistics update every two seconds. Press Ctrl+C to stop watching.
The shell is useful for interactive exploration during development. Rather than switching between terminal tabs to run camel trace, camel get routes, and camel run, you stay in one session and iterate.
Exporting to production runtimes
This is the most powerful feature of the CLI: taking a set of YAML route files that you prototyped with camel run and generating a complete, production-ready Maven project.
Export to Quarkus
camel export --runtime=quarkus \
--gav=com.eipbook:order-router:1.0 \
--directory=order-router-quarkus
This generates:
order-router-quarkus/
├── pom.xml
├── src/
│ └── main/
│ ├── resources/
│ │ ├── application.properties
│ │ └── camel/
│ │ ├── order-router.yaml
│ │ └── order-enricher.yaml
│ └── java/
│ └── (empty — routes are YAML)
The generated pom.xml includes:
- Quarkus BOM at the correct version
camel-quarkus-kafka,camel-quarkus-redis-lettuce,camel-quarkus-rest,camel-quarkus-jackson— every component detected from your route filescamel-quarkus-yaml-dslfor YAML route loading- The Quarkus Maven plugin with
quarkus:devand native build profiles
Your application.properties is migrated from the CLI format to Quarkus format. YAML route files are copied into src/main/resources/camel/, which is where Camel Quarkus auto-discovers them at startup.
Run the exported project immediately:
cd order-router-quarkus
mvn quarkus:dev
Export to Spring Boot
camel export --runtime=spring-boot \
--gav=com.eipbook:order-router:1.0 \
--directory=order-router-spring-boot
The structure is identical but the pom.xml references the Spring Boot starter BOM and camel-spring-boot dependencies instead of Quarkus extensions. The same YAML route files work on both runtimes without modification.
Run the Spring Boot variant:
cd order-router-spring-boot
mvn spring-boot:run
What changes and what stays the same
| Aspect | CLI prototype | Exported project |
|---|---|---|
| Route files | order-router.yaml in working directory |
src/main/resources/camel/order-router.yaml |
| Dependencies | Auto-resolved at startup | Declared in pom.xml |
| Configuration | application.properties in working directory |
src/main/resources/application.properties |
| Container image | Not applicable | mvn package produces a container-ready JAR |
| Native compilation | Not supported | Quarkus: mvn package -Dnative |
| Health checks | CLI built-in | Quarkus SmallRye Health / Spring Boot Actuator |
The route logic does not change. The YAML files are byte-for-byte identical. What changes is the runtime plumbing — dependency management, health endpoints, metrics, container image builds — which is exactly the plumbing that Quarkus and Spring Boot provide.
Export options
| Flag | Description | Example |
|---|---|---|
--runtime |
Target runtime: quarkus, spring-boot, main (standalone Camel Main) |
--runtime=quarkus |
--gav |
Maven group:artifact:version | --gav=com.eipbook:order-router:1.0 |
--directory |
Output directory (default: current directory) | --directory=./exported |
--quarkus-version |
Override the Quarkus BOM version | --quarkus-version=3.37.0 |
--spring-boot-version |
Override the Spring Boot BOM version | --spring-boot-version=4.0.7 |
--camel-version |
Override the Camel version | --camel-version=4.20.0 |
--package-name |
Java package for generated classes | --package-name=com.eipbook.router |
--fresh |
Delete existing target directory before export | --fresh |
The update command
Camel evolves rapidly — new components, deprecated APIs, breaking changes between major versions. The camel update command helps you keep your routes current.
Checking for updates
camel update list
CHECK STATUS DETAIL
Camel version UPDATE 4.19.0 → 4.20.0
Deprecated API usage WARNING toD() with simple language — use to() with dynamic URI
Removed component OK No removed components in use
Property migration WARNING camel.component.kafka.brokerList → camel.component.kafka.brokers
Applying updates
camel update run
This applies OpenRewrite recipes to your route files and configuration. OpenRewrite is a source-code transformation engine — it parses your files, applies migration rules, and writes back the modified source. The CLI bundles Camel-specific recipes for each version upgrade.
What camel update run can do:
- Rename deprecated properties (
brokerListtobrokers) - Update component URIs when component names change
- Replace deprecated EIP options with their successors
- Adjust YAML DSL syntax for breaking changes between Camel versions
What it cannot do:
- Refactor custom Java processors
- Migrate custom CDI beans
- Update third-party library dependencies
For major version upgrades (3.x to 4.x), the CLI’s recipes handle the bulk of the mechanical changes. You still need to review the migration guide for semantic changes — behavior differences that cannot be detected from syntax alone.
Plugins
The CLI architecture is extensible through plugins. Plugins add new top-level commands to the camel CLI.
Installing plugins
# Add Kubernetes commands
camel plugin add kubernetes
# Add Citrus testing support
camel plugin add test
# List installed plugins
camel plugin list
Kubernetes plugin
The Kubernetes plugin adds commands for deploying and managing Camel integrations on Kubernetes directly from the CLI:
# Deploy a route to the current Kubernetes context
camel kubernetes run order-router.yaml
# View logs from the deployed pod
camel kubernetes logs order-router
# Delete the deployment
camel kubernetes delete order-router
This plugin works by running camel export --runtime=quarkus behind the scenes, building a container image, and deploying it to the cluster. It is a convenience wrapper — for production deployments, use the explicit export-and-deploy workflow described in Appendix T.
Test plugin
The test plugin integrates Citrus test capabilities into the CLI:
camel test order-router-test.yaml
Citrus tests can verify that a route produces the expected output for a given input, assert header values, and validate message content — all from YAML test definitions without writing Java. See Appendix W for a full treatment of Camel testing with Citrus.
Command reference
A complete reference of CLI commands, grouped by category.
Running and development
| Command | Description |
|---|---|
camel run <files> |
Run routes from YAML, Java, or XML files |
camel dev <files> |
Alias for camel run --dev — run with live reload |
camel run --dev <files> |
Run with live reload, developer console, and enhanced tracing |
camel run --open-api <files> |
Run and serve generated OpenAPI specification |
camel shell |
Enter interactive shell with tab completion |
camel version |
Print the installed Camel CLI version |
Inspection and monitoring
| Command | Description |
|---|---|
camel ps |
List all running Camel integrations |
camel get routes |
Show route status, exchange counts, and processing times |
camel get health |
Display health check results for all integrations |
camel get kafka |
Show Kafka consumer lag per topic/partition |
camel get endpoint |
Show endpoint statistics — message counts and timing |
camel get context |
Display CamelContext details — version, uptime, component list |
Tracing and debugging
| Command | Description |
|---|---|
camel trace |
Trace live exchanges flowing through routes |
camel trace --filter=<route> |
Trace exchanges for a specific route |
camel trace --filter=fail |
Trace only failed exchanges |
camel debug |
Attach a step-by-step debugger to a running integration |
Infrastructure
| Command | Description |
|---|---|
camel infra list |
List available infrastructure services |
camel infra run <service> |
Start an infrastructure container (Kafka, Redis, etc.) |
camel infra stop <service> |
Stop a running infrastructure container |
Exporting
| Command | Description |
|---|---|
camel export --runtime=quarkus |
Export routes to a Quarkus Maven project |
camel export --runtime=spring-boot |
Export routes to a Spring Boot Maven project |
camel export --runtime=main |
Export routes to a standalone Camel Main project |
Maintenance
| Command | Description |
|---|---|
camel update list |
Check for available version updates and deprecated API usage |
camel update run |
Apply OpenRewrite migration recipes to route files |
camel plugin add <name> |
Install a CLI plugin |
camel plugin list |
List installed plugins |
camel plugin remove <name> |
Uninstall a CLI plugin |
Kubernetes (plugin)
| Command | Description |
|---|---|
camel kubernetes run <files> |
Deploy routes to the current Kubernetes context |
camel kubernetes logs <name> |
Stream logs from a deployed integration |
camel kubernetes delete <name> |
Delete a deployed integration |
Prototype-to-production workflow
This section ties together everything in the appendix. Walk through the complete lifecycle using the shipping domain routes from examples/39-camel-cli/.
Step 1: Write the routes
Create order-router.yaml with the REST API and content-based router. Create order-enricher.yaml with the Kafka consumer and Redis enricher. Create application.properties with broker and Redis connection details.
Three files, no build tooling, no pom.xml.
Step 2: Start infrastructure
If you are not running the Podman stack, use the CLI to spin up Kafka and Redis:
camel infra run kafka redis
Or use the existing Podman stack:
./scripts/setup-stack.sh
Step 3: Run in dev mode
camel run --dev *.yaml
The CLI resolves dependencies, starts the REST API on port 8088, connects to Kafka and Redis, and begins processing.
Step 4: Test the routes
In a second terminal, submit an order:
curl -X POST http://localhost:8088/api/orders \
-H "Content-Type: application/json" \
-H "orderType: EXPRESS" \
-d '{
"orderId": "ORD-9001",
"customerId": "CUST-42",
"item": "Wireless Headphones",
"quantity": 2
}'
Step 5: Trace exchanges
In a third terminal:
camel trace
Watch the exchange flow from the REST endpoint through the content-based router to the Kafka express topic, then from the express topic through the enricher to the enriched topic. Verify that the routing decision matches the orderType header.
Step 6: Inspect route statistics
camel get routes
Confirm that both routes are started, check exchange counts, and verify no failures.
Step 7: Iterate
Edit order-router.yaml — add a new branch for PRIORITY orders, change a log message, adjust the REST path. Dev mode detects the change and reloads within seconds. No restart, no rebuild.
Step 8: Export to Quarkus
When the routes are working correctly:
camel export --runtime=quarkus \
--gav=com.eipbook:order-router:1.0 \
--directory=order-router-quarkus
Step 9: Run as a Quarkus application
cd order-router-quarkus
mvn quarkus:dev
The same routes, the same behavior, now running on the Quarkus runtime with full access to Quarkus extensions, health endpoints, metrics, native compilation, and container image builds.
Step 10: Deploy to Kubernetes
Follow Appendix T to build a container image, generate Kubernetes manifests, and deploy the exported project to Minikube or a production cluster.
The entire lifecycle — from a blank YAML file to a production Kubernetes deployment — uses the same route definitions. The CLI is the on-ramp: prototype fast, validate with tracing and inspection, and export when ready. The route logic never changes; only the runtime packaging evolves.
Key takeaways
camel runis a zero-config runtime — write a YAML route, run it, and dependencies are resolved automatically. No Maven project needed for prototyping.camel traceis your primary debugging tool — see every exchange, every routing decision, every processing step in real time. Filter by route or failure status.camel getcommands provide operational visibility — route status, health checks, Kafka consumer lag, and endpoint statistics from the command line.camel infraspins up infrastructure on demand — Kafka, Redis, PostgreSQL containers without touching Docker Compose or Podman files.camel exportbridges prototype and production — generate a complete Quarkus or Spring Boot Maven project from your YAML routes. Same route files, production-grade runtime.camel updatekeeps routes current — OpenRewrite recipes handle mechanical migration tasks when upgrading Camel versions.- The CLI inspects any Camel application — not just CLI-launched routes. Use
camel ps,camel get, andcamel traceagainst Quarkus and Spring Boot services with the management component enabled.
Further reading
- Camel CLI documentation
- Camel YAML DSL reference
- JBang — the Java runner that powers the CLI
- OpenRewrite Camel recipes
Verification status: unverified. CLI commands reference Apache Camel 4.20.0.