Core Concepts
Architecture
Understand Envoy's control plane, executors, subprocess task runner, streaming pipeline engine, and state stores.
Architecture
What Envoy is made of
Envoy is a single compiled binary that plays three roles depending on how it is started:
- Control plane (
envoy server) — serves the Vue web UI and the REST API, stores all state, schedules triggered runs, and dispatches task runs. - Executor (
envoy executor) — registers with a control plane over HTTP and runs task subprocesses on its behalf. Optional: a control plane configured withexecutor.type: localruns tasks itself. - CLI (
envoy <task>,envoy job run, …) — runs tasks and jobs directly from the terminal with no server at all.
All three paths execute tasks the same way, which is what makes tasks portable across environments.
One run, one subprocess
Every task run executes in its own spawned subprocess. Before dispatch, the control plane resolves everything the run needs into a single self-contained YAML: the task definition (snapshotted at run time), the connector configurations decrypted from the store, and any argument values. The subprocess receives that resolved YAML and nothing else — it has no access to the server's database or encryption key, and it does not know whether its configs came from the UI, a job binding, or a CLI file.
This isolation has practical consequences:
- A crashing or leaking task cannot take the control plane down.
- Runs are killable: stopping a run terminates its process.
- Concurrency is bounded by configuration (
runs.max_concurrenton the server,--max-concurrenton an executor).
The subprocess reports progress back through its stdout/stderr, which the server captures into the run's log store.
The streaming pipeline engine
Inside the subprocess, a task's steps become a Node.js Stream pipeline. Records flow through the steps one at a time with backpressure: a slow destination naturally throttles the source, so datasets never need to fit in memory. Steps can declare per-step concurrency for parallel processing, and batch/spool options for steps that need groups of records rather than single ones. See Run lifecycle for what happens around the pipeline, and Task anatomy for the YAML that defines it.
Control plane responsibilities
Beyond dispatching runs, the control plane owns:
- State — tasks and their versions, job templates, jobs, runs, connectors, triggers, users, and sessions, in a store that is SQLite by default and can be MSSQL or PostgreSQL (
store.typeinenvoy-server.yaml). - Secrets — connector configurations are encrypted at rest with the server's
encryption_key; deployments can also reference secrets from Azure Key Vault. See RBAC, secrets, and hardening. - Scheduling — cron Triggers start job runs without a user in the loop.
- Run logs and metrics — captured per run, stored in a configurable log store (file, database, or VictoriaLogs), and streamed live to the UI.
Executors and topology
The smallest deployment is one container running the control plane with executor.type: local. The default Docker Compose stack splits the roles: a control-plane container and an executor container that authenticate to each other with a shared executor key. Larger deployments add executors for capacity. The trade-offs and configuration are covered in Control plane and executors.
Where the layers live
The three-layer model (Tasks, jobs, and templates) maps onto this architecture cleanly: Tasks and Job Templates are portable YAML (from bundled files or the store), Jobs and their Connector bindings exist only in the control plane's state store, and every execution — however triggered — ends up as the same resolved YAML in a subprocess.
Related
- Tasks, jobs, and templates — the definition layers this runtime executes
- Run lifecycle — statuses, leases, failure policies, retention
- Control plane and executors — deployment topologies in depth