A high-performance, rule-based messaging platform for NATS, providing an internal message router, cron-based scheduled publishing, a bidirectional HTTP gateway, and an automated token manager for secure API integration.
rule-router is a single unified binary with three selectable features, plus a companion auth manager:
- Router (default): A high-throughput NATS-to-NATS message router for internal, event-driven workflows.
- Scheduler: A cron-based scheduler that publishes to NATS and HTTP endpoints on configurable schedules, with full conditions, KV support, and HTTP retry logic.
- Gateway: A bidirectional bridge for integrating external systems with your NATS fabric via webhooks (HTTP → NATS) and outbound API calls (NATS → HTTP).
nats-auth-manager: A standalone utility that securely manages and refreshes API tokens (OAuth2, etc.), storing them in NATS KV for use by the gateway on outbound webhooks.
Features are enabled via config (features.router, features.gateway, features.scheduler) or environment variables (RR_FEATURES_GATEWAY=true). Multiple features can run in a single process.
The platform is designed for performance, security, and flexibility in event-driven architectures.
- High Performance: Microsecond rule evaluation, asynchronous processing, and thousands of messages per second.
- Cron Scheduling: Publish to NATS and HTTP endpoints on cron schedules with timezone support, conditional execution, KV lookups, and HTTP retry logic. HTTP actions can optionally republish the response body to a NATS subject — turning periodic API polling into a normal event-driven flow.
- Array Processing: Native support for batch message processing with array operators and forEach iteration.
- Primitive Message Support: Handle strings, numbers, arrays, and objects at the root - perfect for IoT protocols and simple formats.
- Bidirectional HTTP Gateway:
- Inbound: "Fire-and-forget" webhook ingestion returns
200 OKimmediately for maximum compatibility. Optional per-rule HMAC verification authenticates provider webhooks (GitHub, Shopify, …) as a fail-closed gate — a bad/missing signature returns401before the rule fires. JSON andapplication/x-www-form-urlencodedbodies both decode into addressable fields, and query parameters are available as{@query.name}in their own namespace. - Outbound: "ACK-on-Success" API calls with configurable retries and exponential backoff ensure reliable delivery.
- Synchronous responses: An HTTP rule can return an evaluated/enriched payload as the response (
respondaction), or bridge the request through NATS request/reply (request: true) and return the reply.
- Inbound: "Fire-and-forget" webhook ingestion returns
- NATS Request/Reply: Answer requests on a subject via
msg.Respond(reply: truetrigger +respondaction), with optional queue-group load balancing — exposing rule-driven services over core NATS. - NATS JetStream Native: Built on JetStream pull consumers for durable, scalable, and resilient message processing.
- Powerful Rule Engine:
- Dynamic Conditions: Evaluate message payloads, headers, NATS subjects, HTTP paths, and query parameters.
- Templating: Construct new message payloads, subjects, URLs, and headers using data from the trigger.
- Key-Value Integration: Enrich messages with data from NATS KV stores, with an optional local cache for a ~25x performance boost.
- KV Rule Store: Optionally store rules in a NATS KV bucket with automatic hot-reload on any change. Push rules with
rule-cli kv pushfor a GitOps workflow. - Time-Based Logic: Create rules that only run at certain times of day, on specific days, or within a time window.
- Throttle: Optional per-rule rate limiting on actions (or triggers) with configurable time windows and template-based keys.
mode: leading(default) fires the first match in a window and drops the rest;mode: trailingholds the action and emits the last value when the window closes.
- Cryptographic Security: Verify message integrity and authenticity — NATS NKey signatures for NATS publishers, and shared-secret HMAC verification for inbound webhooks.
- Production Ready: Structured logging, Prometheus metrics, graceful shutdown, and full NATS authentication support.
The platform uses a simple Trigger -> Conditions -> Action model defined in YAML files, loaded from the local filesystem or a NATS KV bucket.
- Triggers define what starts a rule (e.g., a NATS message on
sensors.>, an HTTP POST to/webhooks/github, or a cron schedule). - Conditions define the logic to determine if the action should run (e.g.,
temperature > 30). - Actions define what to do if conditions pass (e.g., publish a new NATS message or make an HTTP call).
» For a complete guide, see the Core Concepts documentation.
Detailed documentation on the rule engine's features can be found in the docs/ directory:
- 01 - Core Concepts: Triggers, Conditions, Actions, and Environment Variables.
- 02 - Gateway: Inbound (HTTP→NATS) and outbound (NATS→HTTP) flows, fire-and-forget vs ACK-on-success semantics,
publishResponse, synchronous responses, and the HTTP↔NATS request/reply bridge. - 03 - Scheduler: Cron triggers, scheduler-specific context, polling-to-eventing, and KV-driven fan-out.
- 04 - System Variables & Functions: Full reference for all
@variables and functions. - 05 - Array Processing: Guide to using
forEachand array operators (any,all,none). - 06 - Primitive & Array Root Messages: How to handle non-object JSON payloads.
- 07 - Security: NKey signature verification for NATS publishers and fail-closed HMAC verification for inbound webhooks.
- 08 - KV Rule Store: Store rules in NATS KV with hot-reload and GitOps push workflow.
- 09 - Patterns: Recipe catalogue from simple routing through stateful cross-source correlation.
- 10 - Troubleshooting: Common failure modes and how to diagnose them.
- 11 - Configuration Reference: Every config section, field, default, and validation bound.
- 12 - Metrics & Observability: Full Prometheus metric catalogue, health checks, example queries and alerts.
- Rule Builder Web UI: Visual rule creation, live YAML preview, in-browser rule testing via WASM, and NATS KV push/pull.
- Docker Deployment: Docker Compose setup for local development and deployment.
Download pre-built binaries from GitHub Releases for your platform. Each release includes all applications and the CLI tool.
# Extract the release archive
tar -xzf rule-router_<version>_<os>_<arch>.tar.gz
# Run with router feature (default)
./rule-router --config config/rule-router.yaml --rules ./rules
# Run with gateway feature
RR_FEATURES_ROUTER=false RR_FEATURES_GATEWAY=true \
./rule-router --config config/http-gateway.yaml --rules ./rules
# Run with scheduler feature
RR_FEATURES_ROUTER=false RR_FEATURES_SCHEDULER=true \
./rule-router --config config/rule-scheduler.yaml --rules ./rules
# Run all features in a single process
RR_FEATURES_GATEWAY=true RR_FEATURES_SCHEDULER=true \
./rule-router --config config/rule-router.yaml --rules ./rules
# Run the auth manager (separate binary)
./nats-auth-manager --config config/auth-manager.yamlA running NATS Server with JetStream enabled is required. See Configure NATS Streams below for setup.
Brings up all services including a NATS server with JetStream — no external dependencies needed.
# Build and start all apps with a bundled NATS server
docker compose --profile nats up -d
# Check that everything is healthy
docker compose ps
# View logs
docker compose logs -f
# Include the web UI on port 3000
docker compose --profile nats --profile web up -d
# Run the CLI tool
docker compose run --rm rule-cli lint /rules
# Tear down (add -v to also remove NATS data)
docker compose downIf you already have a NATS server running, start just the applications and point them to it:
# Start apps only, pointing to your NATS server
NATS_URLS=nats://your-nats-host:4222 docker compose up -d
# Or set it in a .env file
echo 'NATS_URLS=nats://your-nats-host:4222' > .env
docker compose up -dThe repository uses a single parameterized Dockerfile. The rule-router image includes all three features (router, gateway, scheduler) — select which to enable at runtime via config or environment variables:
# Build the rule-router image (includes all features)
docker build --build-arg APP_NAME=rule-router -t rule-router .
# Build companion images
docker build --build-arg APP_NAME=nats-auth-manager -t nats-auth-manager .
docker build --build-arg APP_NAME=rule-cli -t rule-cli .
# Run as router (default)
docker run -d \
-v ./config/rule-router.yaml:/config/rule-router.yaml:ro \
-v ./rules/router:/rules:ro \
-p 2112:2112 \
rule-router --config /config/rule-router.yaml --rules /rules
# Run as gateway
docker run -d \
-e RR_FEATURES_ROUTER=false -e RR_FEATURES_GATEWAY=true \
-v ./config/http-gateway.yaml:/config/http-gateway.yaml:ro \
-v ./rules/http:/rules:ro \
-p 8080:8080 -p 2112:2112 \
rule-router --config /config/http-gateway.yaml --rules /rulesPorts exposed:
| Service | Port | Description |
|---|---|---|
| NATS (optional) | 4222 | Client connections |
| NATS (optional) | 8222 | Monitoring dashboard |
| rule-router (gateway) | 8080 | Inbound webhooks |
| rule-router | 2112 | Prometheus metrics |
| nats-auth-manager | 2113 | Prometheus metrics |
| web (optional) | 3000 | Rule Builder UI |
Configuration files in config/ and rules in rules/ are mounted as volumes, so edits are picked up on restart (or via SIGHUP for hot-reload).
- Go 1.26+
- A running NATS Server with JetStream enabled.
From the root of the repository:
# Build the unified rule-router binary (includes router, gateway, and scheduler features)
go build -o rule-router ./cmd/rule-router
# Build the auth manager
go build -o nats-auth-manager ./cmd/nats-auth-manager
# Build the CLI
go build -o rule-cli ./cmd/rule-cli
# Build the WASM test engine for the web UI (optional)
GOOS=js GOARCH=wasm go build -ldflags="-s -w" -o web/public/tester.wasm ./cmd/wasm/
cp "$(go env GOROOT)/lib/wasm/wasm_exec.js" web/public/For this example, we'll receive a webhook and route it to an internal alerts stream.
# Stream for messages coming from the HTTP gateway
nats stream add WEBHOOKS --subjects "webhooks.>"
# Stream for critical alerts processed by the rule-router
nats stream add ALERTS --subjects "alerts.>"Create a rules/ directory with two rule files.
rules/http_ingress.yaml (For the gateway feature)
This rule listens for inbound webhooks at /webhooks/devices and publishes a standardized message to NATS.
- trigger:
http:
path: "/webhooks/devices"
method: "POST"
conditions:
operator: and
items:
- field: "{status}"
operator: "eq"
value: "error"
action:
nats:
subject: "webhooks.devices.status"
payload: |
{
"device_id": "{device_id}",
"error_code": "{error.code}",
"error_message": "{error.message}",
"received_at": "{@timestamp()}"
}rules/internal_routing.yaml (For the router feature)
This rule listens for the internal status messages and routes critical errors to a dedicated alerts subject.
- trigger:
nats:
subject: "webhooks.devices.status"
conditions:
operator: and
items:
- field: "{error_code}"
operator: gte
value: 5000 # Critical error codes
action:
nats:
subject: "alerts.critical.{device_id}"
passthrough: true # Forward the original message payload
headers:
X-Routed-By: "rule-router"If using Docker Compose, the services are already running (see Option B). For manual runs, you can run both features in a single process or separately.
Option 1: Single process with both features
RR_FEATURES_GATEWAY=true ./rule-router --config config/rule-router.yaml --rules ./rulesOption 2: Separate processes
# Terminal 1: Start the gateway
RR_FEATURES_ROUTER=false RR_FEATURES_GATEWAY=true \
./rule-router --config config/http-gateway.yaml --rules ./rules
# Terminal 2: Start the router
./rule-router --config config/rule-router.yaml --rules ./rulesTerminal 3: Subscribe to the final alerts subject
nats sub "alerts.>"Terminal 4: Send a test webhook
curl -X POST http://localhost:8080/webhooks/devices \
-H "Content-Type: application/json" \
-d '{
"device_id": "sensor-123",
"status": "error",
"error": {
"code": 5001,
"message": "Internal system failure"
}
}'You will see the message appear on the alerts.> subscription, having been processed by both applications.
-
cmd/rule-router: The unified binary containing three features — router (NATS-to-NATS message routing), gateway (bidirectional HTTP-NATS integration), and scheduler (cron-based publishing). Enable features via config or env vars. » View README -
cmd/nats-auth-manager: A standalone service that handles OAuth2 and custom API authentication, storing tokens in NATS KV for use by other services. » View Auth Manager README -
cmd/rule-cli: A powerful command-line utility for linting, scaffolding, and testing your rules offline, enabling CI/CD and ensuring rule correctness. » View CLI README -
web: A visual rule builder web UI. Build rules with a guided form, preview YAML in real time, test rules against sample messages using the Go engine compiled to WebAssembly, and push directly to NATS KV via WebSocket. » View Web UI README
All features expose a shared Prometheus metrics endpoint (default :2112). The full metric catalogue, health-check surface, and example queries/alerts are in 12 - Metrics & Observability. Key metrics include:
Message Processing:
messages_total: Total messages processed by status.rule_matches_total: Total number of times any rule has matched.actions_total: Total actions executed by status.
Array Operations:
foreach_iterations_total{rule_file="..."}: Array elements visited in forEach operations.foreach_filtered_total{rule_file="..."}: Elements dropped by forEachfilterconditions.foreach_actions_generated_total{rule_file="..."}: Actions successfully generated by forEach.
Throttle:
throttle_suppressed_total: Messages dropped by a leading-mode per-rule throttle, by phase (trigger/action).throttle_deferred_total: Trailing-mode throttle lifecycle, by outcome (coalesced/emitted/dropped/error).
HTTP Gateway:
http_inbound_requests_total: (Gateway) Inbound HTTP requests.http_outbound_requests_total: (Gateway) Outbound HTTP requests.
Scheduler:
rules_active: Number of schedule rules registered.action_publish_failures_total: Failed scheduled publish attempts.
Auth Manager:
authmgr_auth_success_total: Successful authentications by provider.authmgr_auth_failures_total: Failed authentications by provider.
This project is licensed under the MIT License - see the LICENSE file for details.