Local Mode
Run Expanso Edge as a standalone API server for rapid pipeline development and testing—no orchestrator or cloud connection required.
What is Local Mode?
Local mode runs Expanso Edge with a built-in API server that accepts job submissions directly via the CLI. Perfect for:
- First-time users - Get started without infrastructure
- Pipeline development - Fast iteration on pipeline configurations
- Debugging - Test pipelines locally before deployment
- CI/CD - Automated pipeline testing
What you get:
- ✅ Full pipeline processing capabilities
- ✅ REST API for job submission
- ✅ CLI integration for job management
- ✅ Local state storage
- ✅ Zero configuration needed
What you don't get:
- ❌ Multi-node coordination
- ❌ Centralized orchestration
- ❌ Job scheduling and assignment
- ❌ Fleet management
- ❌ Web UI for monitoring
Quick Start (5 Minutes)
Step 1: Start Edge in Local Mode
expanso-edge run --local
You'll see output like:
INFO Local mode enabled - no orchestrator connection required
INFO API server starting on http://localhost:9010
INFO Ready to accept jobs via API
The edge node is now running and ready to accept pipeline jobs on port 9010.
Step 2: Create a Simple Job
Create hello-job.yaml:
name: hello-world
description: Simple hello world pipeline
type: pipeline
config:
input:
generate:
count: 5
interval: "1s"
mapping: |
root.message = "Hello from pipeline!"
root.timestamp = now()
root.count = count("messages")
pipeline:
processors: []
output:
stdout:
codec: lines
Step 3: Submit the Pipeline
In a new terminal, configure the CLI to point to your local edge, then submit the pipeline:
# Point CLI to local edge
export EXPANSO_CLI_ENDPOINT=http://localhost:9010
# Deploy the job
expanso-cli job deploy hello-job.yaml
You should see:
✓ Job deployed successfully
Job ID: job-abc123
Step 4: Monitor the Job
Watch the output in the terminal where expanso-edge is running. You'll see:
{"message":"Hello from pipeline!","timestamp":"2024-11-01T12:00:00Z","count":1}
{"message":"Hello from pipeline!","timestamp":"2024-11-01T12:00:01Z","count":2}
{"message":"Hello from pipeline!","timestamp":"2024-11-01T12:00:02Z","count":3}
{"message":"Hello from pipeline!","timestamp":"2024-11-01T12:00:03Z","count":4}
{"message":"Hello from pipeline!","timestamp":"2024-11-01T12:00:04Z","count":5}
🎉 Success! You've run your first pipeline in local mode.
See the Common Errors section below for solutions to job format errors, port conflicts, and connection issues.
CLI Commands for Local Mode
Configure CLI for Local Edge
Set the environment variable once to point all CLI commands to your local edge:
export EXPANSO_CLI_ENDPOINT=http://localhost:9010
Tip: Add this to your ~/.bashrc or ~/.zshrc for persistent configuration.
Submit a Job
expanso-cli job deploy my-pipeline.yaml
Alternative: Use --endpoint flag for one-off commands:
expanso-cli job deploy my-pipeline.yaml --endpoint http://localhost:9010
List Running Jobs
expanso-cli job list
Get Job Status
expanso-cli job describe <job-id>
Stop a Job
expanso-cli job stop <job-id>
View Job Executions
expanso-cli job executions <job-id>
Configuration
Custom API Port
By default, local mode listens on http://localhost:9010. To change:
expanso-edge run --local --api-listen :8080
Then update your environment variable:
export EXPANSO_CLI_ENDPOINT=http://localhost:8080
Data Directory
Local mode stores state in a local database. Specify a custom location:
expanso-edge run --local --data-dir ./my-data
Enable Debug Logging
See detailed execution logs:
expanso-edge run --local --log-level debug
Or trace level for even more detail:
expanso-edge run --local --log-level trace
Common Workflows
Development Iteration Loop
# Terminal 1: Start edge once
expanso-edge run --local -v
# Terminal 2: Set endpoint and iterate
export EXPANSO_CLI_ENDPOINT=http://localhost:9010
# Deploy v1
expanso-cli job deploy v1-pipeline.yaml
# ... test and observe output ...
# Update pipeline file, deploy v2
expanso-cli job deploy v2-pipeline.yaml
# ... test changes ...
Testing Multiple Pipelines
Run multiple pipelines concurrently:
# Set endpoint
export EXPANSO_CLI_ENDPOINT=http://localhost:9010
# Submit first pipeline
expanso-cli job deploy pipeline-a.yaml
# Submit second pipeline (runs in parallel)
expanso-cli job deploy pipeline-b.yaml
# List all running jobs
expanso-cli job list
Clean State Between Runs
Stop edge, remove state, and restart:
# Stop edge (Ctrl+C)
# Remove local state
rm -rf ./data # or your custom --data-dir path
# Restart fresh
expanso-edge run --local
Examples
Example 1: File Processing Pipeline
Process log files locally:
Create logs-job.yaml:
name: log-processor
description: Process log files and extract errors
type: pipeline
config:
input:
file:
paths: ["/var/log/app/*.log"]
codec: lines
pipeline:
processors:
- mapping: |
# Parse JSON logs
root = this.parse_json()
# Only keep errors
root = if this.level != "ERROR" { deleted() }
output:
file:
path: ./errors.log
codec: lines
Run:
# Terminal 1: Start edge
expanso-edge run --local
# Terminal 2: Submit job
export EXPANSO_CLI_ENDPOINT=http://localhost:9010
expanso-cli job deploy logs-job.yaml
Example 2: Data Transformation
Transform CSV to JSON:
Create csv-transform-job.yaml:
name: csv-to-json
description: Transform CSV users file to JSON
type: pipeline
config:
input:
file:
paths: ["./users.csv"]
codec: lines
pipeline:
processors:
- mapping: |
# Skip header row
root = if @message_number == 0 { deleted() }
# Parse CSV
let parts = this.split(",")
root = {
"name": $parts.index(0),
"email": $parts.index(1),
"age": $parts.index(2).number()
}
output:
file:
path: ./users.json
codec: lines
Run:
# Terminal 1: Start edge
expanso-edge run --local
# Terminal 2: Submit job
export EXPANSO_CLI_ENDPOINT=http://localhost:9010
expanso-cli job deploy csv-transform-job.yaml
Example 3: HTTP API Testing
Test an HTTP input locally:
Create http-receiver-job.yaml:
name: webhook-receiver
description: Receive and process webhook data
type: pipeline
config:
input:
http_server:
address: "0.0.0.0:8081"
path: /webhook
pipeline:
processors:
- mapping: |
root = this.parse_json()
root.processed_at = now()
output:
stdout:
codec: lines
Run:
# Terminal 1: Start edge
expanso-edge run --local
# Terminal 2: Submit job
export EXPANSO_CLI_ENDPOINT=http://localhost:9010
expanso-cli job deploy http-receiver-job.yaml
# Terminal 3: Send test data
curl -X POST http://localhost:8081/webhook \
-H "Content-Type: application/json" \
-d '{"event":"test","data":"hello"}'
Common Errors
Job Format Requirements
When submitting jobs via the CLI or API in local mode, you must use the job wrapper format:
name: my-job # Required: job name
description: "..." # Optional: description
type: pipeline # Required: job type
config: # Required: pipeline configuration
input: { ... }
pipeline: { ... } # Required even if empty
output: { ... }
Valid job types:
pipeline- Standard data pipeline (most common)query- One-time query jobupdate- Update existing jobconfig- Configuration job
Common errors:
❌ "job type cannot be empty"
# Missing wrapper - won't work
input:
generate: { ... }
✅ Solution: Add wrapper structure
name: my-job
type: pipeline
config:
input:
generate: { ... }
pipeline:
processors: []
output:
stdout: {}
❌ "pipeline component is required"
name: my-job
type: pipeline
config:
input: { ... }
output: { ... }
# Missing pipeline section
✅ Solution: Include pipeline section (even if empty)
name: my-job
type: pipeline
config:
input: { ... }
pipeline:
processors: [] # Required even if no processors
output: { ... }
Note: This wrapper format is specific to job submissions via CLI/API. When using expanso-edge run --config pipeline.yaml (standalone mode covered in Build Your First Pipeline), you use the pipeline config format directly without the wrapper.
Wrong Port Configuration
Error: Error: failed to connect to edge
Cause: CLI is trying to connect to the wrong port. The default port is 9010, not 8080.
Solution:
# Correct default endpoint
export EXPANSO_CLI_ENDPOINT=http://localhost:9010
# Or if you started edge with custom port:
expanso-edge run --local --api-listen :8080
export EXPANSO_CLI_ENDPOINT=http://localhost:8080
Missing Environment Variable
Issue: CLI commands fail even though edge is running
Cause: EXPANSO_CLI_ENDPOINT not set, and CLI defaults to cloud endpoint
Solution:
# Set for current session
export EXPANSO_CLI_ENDPOINT=http://localhost:9010
# Or use --endpoint flag for one-off commands
expanso-cli job deploy my-job.yaml --endpoint http://localhost:9010
# Make permanent (add to ~/.bashrc or ~/.zshrc)
echo 'export EXPANSO_CLI_ENDPOINT=http://localhost:9010' >> ~/.bashrc
Troubleshooting
Port Already in Use
Error: Error: listen tcp :9010: bind: address already in use
Solution: Use a different port:
# Terminal 1: Start with custom port
expanso-edge run --local --api-listen :8080
# Terminal 2: Update environment variable
export EXPANSO_CLI_ENDPOINT=http://localhost:8080
expanso-cli job deploy my-pipeline.yaml
CLI Can't Connect
Error: Error: failed to connect to edge
Solutions:
- Verify edge is running: Check terminal for "API server starting" message
- Check the endpoint: Use
--endpointflag if not using default port - Verify firewall: Ensure localhost connections are allowed
Job Not Running
Issue: Job submitted but nothing happening
Debug steps:
-
Check job status:
export EXPANSO_CLI_ENDPOINT=http://localhost:9010
expanso-cli job list
expanso-cli job describe <job-id> -
Check edge logs:
# Restart with debug logging
expanso-edge run --local --log-level debug -
Verify pipeline config:
# Test with minimal pipeline first
State Issues
Issue: Old jobs still appearing
Solution: Clean state directory:
# Stop edge
# Remove state
rm -rf ./data # or your --data-dir path
# Restart
expanso-edge run --local
API Reference
When running in local mode, Edge exposes these API endpoints:
Submit Job
POST /api/v1/jobs
Content-Type: application/yaml
[pipeline configuration]
Example:
curl -X POST http://localhost:9010/api/v1/jobs \
-H "Content-Type: application/yaml" \
--data-binary @my-pipeline.yaml
List Jobs
GET /api/v1/jobs
Get Job Details
GET /api/v1/jobs/{job-id}
Stop Job
POST /api/v1/jobs/{job-id}/stop
Delete Job
DELETE /api/v1/jobs/{job-id}
Health Check
GET /health
Comparison: Local Mode vs. Orchestrated Mode
| Feature | Local Mode | Orchestrated Mode |
|---|---|---|
| Setup | expanso-edge run --local | Requires orchestrator + bootstrap |
| Job Submission | Direct API/CLI | Via orchestrator |
| Multi-node | No | Yes |
| Job Scheduling | Manual | Automatic |
| Web UI | No | Yes (orchestrator) |
| State Storage | Local BoltDB | Centralized |
| Best For | Development, testing | Production deployments |
Next Steps
Once you're comfortable with local mode:
- Deploy to Production - Set up Expanso Cloud and connect edge nodes
- Learn Bloblang - Master data transformations
- Explore Components - Browse 200+ inputs, processors, and outputs
- Testing & Debugging - Advanced troubleshooting techniques
Tips
Fast Feedback: Local mode starts instantly - no bootstrap, no credentials needed.
Use for CI/CD: Perfect for automated pipeline testing in continuous integration.
Combine Approaches: Use local mode for development, then deploy the same pipeline configurations to production via orchestrator.
Multiple Instances: Run multiple edge instances on different ports for parallel testing:
# Terminal 1
expanso-edge run --local --api-listen :9010
# Terminal 2
expanso-edge run --local --api-listen :9011 --data-dir ./data2
# Terminal 3: Point CLI to first instance
export EXPANSO_CLI_ENDPOINT=http://localhost:9010