Releasing soon Vigo is in alpha and closing in on its first stable release. Expect breaking changes between releases until then — we're looking for testing partners with meaningful fleets across diverse architectures. Learn more →

Technical Comparison

A factual comparison of Vigo against five established configuration management systems — Puppet, CFEngine, Chef, Ansible, and SaltStack — covering capacity, architecture, performance and scale, security, configuration expressiveness, idempotency, and operational characteristics.

Where capacity and performance are compared, all tools are evaluated against the same reference hardware — the box Vigo was load-tested on: an 8 vCPU / 32 GB server (GCP, off-box load). Capacity is compared at a common check-in cadence rather than each tool's default, so the numbers are apples-to-apples — the capacity matrix below shows every tool at 1s, 5s, and 5m side by side. Vigo's ceiling is cadence-dependent — CPU-bound at a 1-second cadence, memory-bound at a relaxed one — and it is the only system here that sustains a 1-second cadence at all; the competitor figures are scaled from each vendor's documented requirements onto the same box, cited where available.

On Vigo's numbers. Vigo has no production deployment, but the server has now been load-tested end to end, off-box on GCP, on an 8 vCPU / 32 GB host. Every Vigo figure below is one of: (a) a Go microbenchmark from the codebase (go test -bench), (b) a value read directly out of the source (unsafe.Sizeof, registry counts, binary size on disk), (c) a result from that load test, or (d) a single ad-hoc observation from the developer's home-lab fleet — labelled as such. The single-host ceiling has two limits, and which binds depends on the check-in cadence: at a 1-second cadence the server is CPU-bound (~7,450 envoys on 8 vCPU — the per-check-in signature-verify and processing work), and at a relaxed 30–60-second cadence it is memory-bound (~30,000 envoys safe on a 32 GB host, ~45,000 the OOM wall) at ~623 KB of all-in live heap per envoy. The full matrix and methodology are in the sizing analysis. Read the comparison as architecture-and-cost; the capacity figures are measured, not a production guarantee.

Capacity on the test rig (8 vCPU / 32 GB server)

Sustainable node count at three check-in cadences on the same box. Vigo rises with the cadence, then plateaus on RAM — at 1s the per-check-in CPU binds (~7,450), and by 5s it has reached the held-connection memory ceiling (~30,000 on 32 GB), where it stays however much slower it then runs. Every other tool does per-node server work — catalog compile, state render, report ingest — on each check-in, so its capacity falls steeply as the cadence tightens, and at 1s the poll-compile designs are far below the cadence they were built for.

System 1-second 5-second 5-minute What binds — and how it moves with cadence
Vigo ~7,450 ~30,000 ~30,000 At 1s, per-check-in CPU binds (~1 vCPU / 1,000 nodes); by 5s it hits the held-connection memory ceiling (~623 KB all-in/envoy → ~30,000 on 32 GB) and plateaus. Scales with cores at 1s, with RAM when relaxed. The only system here that sustains a 1-second cadence.
Puppet <1 ~1–3 ~85–165 Catalog-compile CPU — the master recompiles per node per run. PE's 8-core tier is ~500 nodes at its 30-min default; held to 5m (6× faster) it drops to ~85–165, and sub-minute cadence is below its compile time.
Chef ~6 ~28 ~1,665 Cookbook serving + node-object / search-index writes (disk-IOPS bound). The vendor's own 8-core / 32 GB tier sustains 333 runs/min = 10,000 nodes at the 30-min default; retimed to 5m, ~1,665.
Ansible N/A N/A N/A Push model — no poll loop. One 8 vCPU / 32 GB node drives ~170 hosts in parallel per run (SSH-fork-bound); total fleet = forks × run-window ÷ playbook runtime. Not a cadence the way a pull tool is.
Salt ~tens ~hundreds ~2,400 MWorker state-render CPU. Salt publishes no capacity table; from its one sizing rule (≤ 1.5 worker threads/core × 200 minions/thread) an 8-core master holds ~2,400 minions event-driven, falling steeply as scheduled-highstate cadence tightens.
CFEngine ~11 ~55 ~3,300 / ~10–15k⁺ Enterprise hub: PostgreSQL report ingest (~3,300 here). Community (no reporting DB): cf-serverd just serves policy, scaling to ~10–15k⁺ — but with no reporting/coverage story.

Reading the table. Vigo is the only system that sustains a 1-second cadence at all — at that cadence every poll-compile tool is hundreds to thousands of times smaller, because each recompiles a catalog (Puppet) or re-renders/re-ingests state (Chef, Salt, CFEngine) on every check-in, work those servers were built to do every 30 minutes, not every second. The 5-minute column is the closest to common ground, but even there it holds Puppet and Chef to 6× their 30-minute default — at their native 30-minute cadence on this box they do more (Puppet ~500, Chef ~10,000); the cells show the strict common-cadence figures, scaled from each vendor's documented requirements (sources in Vendor-documented requirements below). Vigo's own column rises from ~7,450 at 1s and plateaus at ~30,000 once the cadence relaxes past ~5s, because held-connection memory — not request rate — then sets the ceiling. The poll-compile competitors are CPU- or ingest-bound on this box well before RAM matters; Vigo converts RAM into node capacity and cores into cadence headroom.

The rest of this document is why: the architecture that produces that number, the per-check-in mechanics behind it, and how Vigo stacks up on the other axes that matter.

Architecture at a Glance

That capacity gap is architectural — it falls out of how each system is built. At a glance:

Vigo Puppet Chef Ansible Salt CFEngine
Model Agent pull (gRPC) Agent pull (HTTPS) Agent pull (HTTPS) Agentless push (SSH) Agent pull+push (ZeroMQ) Agent pull (custom)
Server language Go Ruby/JRuby + Clojure (PuppetDB) Ruby + Erlang (Chef Server) Python Python C
Agent language Rust Ruby + C (Facter) Ruby None (SSH) Python C
Config language YAML Puppet DSL Ruby DSL YAML + Jinja2 YAML + Jinja2 Promise DSL
Transport security gRPC over mTLS + ED25519 signatures HTTPS + client certs HTTPS + API tokens SSH ZeroMQ + AES Custom TLS
State store (server) SQLite PostgreSQL (PuppetDB) PostgreSQL None SQLite/MySQL/PostgreSQL None
State store (agent) LMDB YAML cache JSON cache None Msgpack cache BerkeleyDB
Agent binary size ~8.1 MiB x86_64 / ~6.2 MiB arm64 (static musl, measured) ~200 MB (Ruby + gems) ~100 MB (omnibus) 0 (agentless) ~50 MB (Python + deps) ~3 MB

The pattern that drives the capacity table: Vigo keeps fleet state in process (Go, SQLite) and does almost nothing per check-in, while the pull-compile tools (Puppet, Chef, Salt) do per-node server work — catalog compilation, state rendering — on every run. The next section is that mechanism in detail.

Performance and Scalability

The capacity figures trace to one thing: what each system does on every check-in.

Check-in hot path

Vigo's check-in path is designed for zero database operations. The FleetIndex (in-memory envoy index) provides O(1) lookups. Config matching is pre-computed at load time. The only I/O on the check-in path is the gRPC round-trip itself.

Puppet's agent check-in triggers catalog compilation on the server — the Puppet master evaluates the node's manifest, resolves Hiera data, compiles a resource graph, and serializes it. This involves Ruby interpretation, PuppetDB queries, and potentially Hiera backend lookups. At scale, compile masters are needed.

Chef's check-in downloads cookbooks and converges locally — the server load is lighter (just serving cookbook files), but the client does significant work resolving recipes.

Salt's check-in is lightweight (ZeroMQ message) but state compilation happens on the master.

CFEngine's agent evaluates promises locally from cached policy — the server interaction is minimal (just policy distribution).

Verdict: Vigo and CFEngine have the lightest agent-side check-in paths. Puppet's is the heaviest. On the server side, Vigo holds fleet state in process — the fixed EnvoyState struct is 416 bytes (unsafe.Sizeof, server/fleet/index.go), though the resident cost per envoy is dominated by the per-envoy trait map (Traits map[string]string — dozens to low-hundreds of keys on a typical host) and the bounded recent-run history, so the real figure is materially larger and fleet-dependent. By contrast, CFEngine Enterprise's reporting hub documents ~8 MB per node in PostgreSQL. Vigo's measured single-host ceiling is cadence-dependent — CPU-bound at a 1-second cadence (~7,450 on 8 vCPU), memory-bound at a relaxed cadence (~30,000 on a 32 GB box at ~623 KB of all-in heap per envoy); see the capacity table above.

Check-in characteristics

What happens per check-in Server-side computation Practical minimum interval
Vigo In-memory FleetIndex lookup, pre-built policy cache copy, async batched DB write ED25519 verify ~53 µs (benchmarked — the dominant cost); rest of the cache-hit path <1 µs; end-to-end including gRPC/protobuf/TLS framing not separately benchmarked 1s load-tested (sizing analysis); on a non-trivial policy the agent's own convergence-cycle time, not the configured interval, is the practical floor
Puppet Parse manifests, resolve Hiera data, query PuppetDB, compile catalog graph, serialize Significant — Ruby/JRuby interpretation, multiple DB queries ~5 minutes
Chef Resolve run list, serve cookbook files, update node object Moderate — cookbook file serving + PostgreSQL writes ~5 minutes
Ansible (Push model — no agent check-in. Controller compiles and pushes via SSH.) N/A for check-in; compilation happens on the controller N/A
Salt Compile state tree, resolve pillar data, serialize Moderate — Python state compilation per minion ~1 minute
CFEngine Serve flat policy files; Enterprise hub ingests run reports Minimal for policy serving; moderate for report ingestion ~1 minute

The check-in path is cheap — its dominant cost is the ~53 µs ED25519 verify, with everything else on the cache-hit path under a microsecond — which is what makes sub-minute intervals plausible at all, and why Vigo's "practical minimum interval" is the only sub-minute entry in the table. The sizing analysis works through the measured CPU, memory, and network at a 1-second check-in interval — the most demanding cadence — row by row; at that cadence the binding limit is CPU, and only as the cadence relaxes past ~4–6s does RAM bind first.

Vendor-documented requirements

Documented capacity at vendor-recommended hardware Vendor source
Puppet Up to 2,500 nodes on standard architecture (12 cores, 24 GB RAM). Large architecture (2,500-20,000) requires 16 cores, 32 GB primary + dedicated compilers (6 cores, 12 GB each, adding 1,500-3,000 nodes each). Extra-large (20,000+) adds a dedicated PE-PostgreSQL node (16 cores, 128 GB). PE 2025 Hardware Requirements
Chef Minimum 4 GB RAM (under 33 client runs/min). Disk allocation of ~2 MB per node. Chef Infra Server is deprecated (EOL November 2026), replaced by Chef 360 Platform. Chef System Requirements
Ansible ~1 GB per 10 forks + 2 GB base. 4 forks per CPU core baseline. 400 forks requires ~42 GB RAM. Each fork ~100 MB. AAP 2.5 System Requirements
Salt 5,000-50,000 minions per master depending on hardware. 8 GB and 8 cores sufficient for ~1,200 minions. Documentation notes 50,000 minions possible on 64-bit OS without modification. Salt at Scale
CFEngine Minimum 8 MB RAM per bootstrapped agent on the Enterprise hub. 5,000 hosts requires 40 GB RAM, 500 GB disk. Community edition without reporting hub is lighter. CFEngine 3.26 Installation
Vigo No vendor-documented capacity (no production deployment, no end-to-end load test). Measured microbenchmarks (go test -bench, dev hardware): ED25519 payload verify ~53 µs (the dominant per-check-in cost — BenchmarkVerifyPayload); the rest of the cache-hit check-in path totals <1 µs (timestamp check ~32 ns, pubkey lookup ~143 ns, policy-cache hit ~19 ns, per-envoy stub customization ~300 ns, in-memory mark-seen ~170 ns); policy-bundle rebuild on a cache miss ~5.5 µs on a small test config (BenchmarkBuildPolicyBundle, config-size dependent); EnvoyState struct 416 B. End-to-end load test (8 vCPU / 32 GB, GCP off-box): cadence-dependent — CPU-bound at a 1s cadence (~7,450 safe on 8 vCPU), memory-bound at a relaxed 30–60s cadence (~30,000 safe, ~45,000 OOM) at ~623 KB of all-in heap per envoy. sizing analysis

These are the figures the capacity matrix is scaled from. Note that the poll-compile competitors (Puppet, Salt, and CFEngine's Enterprise hub) are CPU- or report-ingest-bound on this box well before RAM matters, so their extra RAM goes unused — the opposite of Vigo, which converts RAM directly into node capacity and cores into cadence headroom.

Server memory per node

Per-node server memory Source
Vigo 416 B fixed struct; larger in practice (trait map + run history dominate) unsafe.Sizeof(EnvoyState{}), server/fleet/index.go
Puppet Varies by facts/catalog size PuppetDB stores full fact sets + catalogs in PostgreSQL
Chef ~2 MB disk per node Chef docs: "allocate 2 MB for each node"
Ansible ~100 MB per concurrent fork Red Hat docs: "1 GB per 10 forks"
Salt Varies by pillar/state complexity No per-envoy figure documented
CFEngine ~8 MB per node (Enterprise hub) CFEngine docs: "not lower than 8MB per bootstrapped agent"

Agent resource consumption

Memory (idle) CPU (convergence) Disk
Vigo ~20–25 MB RSS¹ Minimal (compiled Rust) ~8 MiB binary (x86_64) / ~6 MiB (arm64) + LMDB state
Puppet ~200 MB RSS (Ruby VM) High (Ruby interpretation) ~200 MB + YAML cache
Chef ~150 MB RSS (Ruby VM) High (Ruby interpretation) ~100 MB + cookbook cache
Salt ~80 MB RSS (Python) Moderate ~50 MB + state cache
CFEngine ~5 MB RSS Minimal (compiled C) ~3 MB binary + BDB

¹ Single observed sample from a long-running home-lab envoy (agent_self.rss_bytes); not yet characterized across operating systems, uptimes, or policy weights — treat as indicative, not a spec. The static binary is ~8 MiB on disk.

Vigo is close to CFEngine for resource consumption and well under the Ruby/Python-based tools (Puppet, Chef, Salt). This matters for edge computing, IoT, containers, and cost-conscious cloud deployments.

Offline operation

Cached convergence Pending results Automatic reconnect
Vigo Yes (signed bundles in LMDB, configurable TTL) Yes (queued in LMDB, drained on reconnect) Yes (exponential backoff)
Puppet Yes (cached catalog) No (results dropped) Yes
Chef No No Yes
Salt Partial (cached states) No Yes
CFEngine Yes (cached promises) No Yes (autonomous)

Vigo's offline convergence is the most complete — signed policy bundles with TTL, local trait evaluation, results queuing, and automatic drain on reconnect. CFEngine's autonomous operation is philosophically similar but lacks the results queue.

Scaling architecture

Horizontal approach Automatic failover Config sync Enrollment routing
Vigo Hub-spoke spanner Yes (auto-drain at configurable threshold) Yes (tar.gz push on publish) Yes (hostname pattern matching)
Puppet Compile masters + PuppetDB replication Manual Via code manager / r10k Via ENC or Hiera
Chef Multi-org, Chef HA (deprecated), Automate Manual Via Chef Server replication N/A
Ansible Tower/AWX clusters Via HA proxy Via SCM (git) N/A (push model)
Salt Multi-master (syndic) Manual failover Via gitfs Via top.sls targeting
CFEngine Hub-spoke (Mission Portal) Manual Via policy hub push Via classes

Past a single host's safe ceiling, Vigo federates with spanner — peer-equal bolts, each holding its own slice of the fleet — rather than the compile-master / replication tiers the pull-compile tools reach for.

Transport and Security

Authentication model

Vigo uses three-layer authentication: mTLS for the transport, ED25519 signature verification on every agent payload (timestamp + body signed with agent's private key, verified against stored public key), and one-time bcrypt-hashed enrollment tokens. This means even if TLS is somehow compromised, an attacker can't forge agent requests without the private key.

Puppet uses HTTPS with client certificates — solid but single-layer. No per-request payload signing. Chef uses HTTPS with API tokens (RSA-signed requests) — similar to Vigo but with RSA instead of ED25519. Salt uses AES-encrypted ZeroMQ with a shared master key — any agent that has the master key can impersonate any other agent. Ansible uses SSH — strong authentication but requires key distribution.

CFEngine uses its own TLS implementation with host key verification. Similar trust model to Puppet but without a standard PKI.

Verdict: Vigo and Chef have the strongest per-request authentication. Salt's shared-key model is the weakest for multi-tenant environments.

Secrets management

Approach Secrets in DB? Secrets in config files? Secrets in logs?
Vigo secret: prefix resolves from encrypted local store or external API. Fail-fast if provider unreachable. Never Never (prefix only) Never (redacted)
Puppet Hiera + eyaml (encrypted YAML values) or external lookup Via Hiera backends Encrypted inline Possible without care
Chef Encrypted data bags or Chef Vault In data bags (encrypted) In recipes (encrypted) Possible
Ansible ansible-vault (encrypts whole files) N/A Encrypted files on disk no_log: true required
Salt Pillars with GPG encryption In pillar (encrypted) In pillar files Possible
CFEngine No built-in secrets management N/A Plaintext or custom No built-in protection

Vigo's approach is the cleanest architecturally — secrets are never stored alongside config, never touch the database, and the resolution is a first-class server-side operation rather than an encryption layer bolted onto the config format.

Configuration Expressiveness

Config language comparison

Capability Vigo Puppet Chef Ansible Salt CFEngine
Language type YAML Custom DSL Ruby YAML + Jinja2 YAML + Jinja2 Promise DSL
Turing complete No Yes Yes Effectively (Jinja2) Effectively (Jinja2) Yes
Conditionals when: expressions, case/match, conditional_block if/elsif/else, case, selectors Ruby if/case when: conditions, Jinja2 Jinja2 if/else ifvarclass, or, and
Iteration foreach: on resources and modules (a module instantiated once per list item — the defined-type analog) each, resource collectors Ruby loops loop, with_items Jinja2 loops slist iteration
Functions Built-in when: builtins (+ tag()/host()/trait() in fleet: selectors) 100+ stdlib functions Ruby methods 100+ filters + plugins Jinja2 filters 50+ body functions
Data hierarchy common.vgo directory inheritance (unbounded depth; modules/roles accumulate, vars last-wins) → role includes: → match-block vars → environments.vgo overrides Hiera (unlimited depth, pluggable backends, per-key merge strategies) Attributes (role → env → node) Variable precedence (22 levels) Pillar (targeted data) def.json augments
Cross-node config fleet: lookup — a var resolved server-side at check-in from the live fleet trait index (LB pools, monitoring targets, cluster member lists) Exported resources + collectors (via PuppetDB) search() over the Chef Server index hostvars/groups within a play Salt Mine Hub-served collected data
Custom resource types type: custom executor (JSON protocol) Defined types + custom types (Ruby) Custom resources (Ruby) Custom modules (Python) Custom states (Python) Custom promise types
Template engine Go templates in content: & resource attributes — interpolation only, no {{ if }}/{{ range }} (the one exception: a fleet: select: is a full Go template, server-side) ERB everywhere ERB everywhere Jinja2 everywhere Jinja2 everywhere Variable expansion

Vigo intentionally keeps content:/attribute templates interpolation-only — no control flow in a config file's body — to prevent the "templates in filenames and commands, {{ if }} in every config" anti-pattern that plagues Ansible and Salt deployments. Per-instance shaping is a when:-gated companion resource or a narrower fleet: query. This is a readability trade-off — less flexible, but configs are auditable without evaluating expressions and modlint can statically validate a whole stockpile.

Composition model

Vigo's six-layer composition — directory inheritance (common.vgo) → glob matching → roles with includes: → modules (with ordering, and module-level foreach:) → resource tools (foreach:/case:/conditional_block:/when:/fleet:) → templates — covers most real-world cases without a programming language. See Composition Patterns for detailed examples.

Puppet's class/defined-type system is still more expressive for deep abstraction — unlimited class composition vs. Vigo's single-level role includes:, typed parameters vs. Vigo's untyped vars:/.Each items, and arbitrary logic inside a defined-type body vs. Vigo's {{ .Each.x }} interpolation + when:-gated resources. But the core "instantiate a parameterized resource group N times" pattern that Puppet defined types and Chef custom resources are built on is now a Vigo primitive too: a module referenced with foreach: ({name: vhost, foreach: vhosts, key: server_name}vhost[www.example.com], …). Vigo's module system is simpler; the remaining gap is depth, not the abstraction itself.

Ansible's role system is the closest analog to Vigo's roles, but Ansible roles can include tasks, handlers, files, templates, defaults, vars, and meta — a more complex structure. Vigo's roles are just named module lists.

Verdict: Puppet and Chef win on raw expressiveness. Vigo and Ansible/Salt win on accessibility. CFEngine's promise DSL is powerful but has the steepest learning curve.

Idempotency and Resource Model

All six tools enforce idempotency — check current state, act only if drift is detected. The differences are in depth and frequency.

Vigo's idempotency is enforced continuously, not just applied once at deploy time. Every resource executor follows a strict check → act → verify cycle on every convergence pass, and the agent runs a full pass every check-in interval. At 15-second intervals, this means drift from manual changes, package upgrades, cron jobs, or external automation is detected and corrected within seconds — not minutes or hours. This is what makes Vigo a continuous enforcement engine rather than a configuration deployment tool.

Resource type coverage

Resource type Vigo Puppet Chef Ansible Salt CFEngine
File (content, permissions, owner) Yes Yes Yes Yes Yes Yes
Package (install, remove, version) Yes Yes (20+ providers) Yes Yes Yes Yes
Service (start, stop, enable) Yes Yes Yes Yes Yes Yes
User/Group Yes Yes Yes Yes Yes Yes
Cron Yes Yes Yes Yes Yes Yes
Repository (apt, yum) Yes Yes Yes Yes Yes Via commands promises
Source package (download, extract) Yes Via puppet-archive Yes Yes Yes Via commands promises
Non-repo package (.deb/.rpm/.msi from URL) Yes Via package with source Via remote_file + dpkg Via apt deb:/dnf URL Via pkg.installed sources Via commands promises
Exec (command, guards) Yes Yes Yes Yes Yes Yes (commands promises)
Mount Yes Yes Yes Yes Yes Yes (storage promises)
SELinux contexts Yes Yes Yes Yes Yes No
Firewall (iptables, pf) Yes (UFW, pf, Windows Firewall) Via puppetlabs-firewall No (use exec) Yes No (use exec) No
Systemd dropin Yes Yes Yes Partial No No
File line editing Yes (file_line, blockinfile, replace, field_edit, ini, json_file, stream_edit) Via file_line/augeas Via line cookbook lineinfile/blockinfile file.line Yes (edit_line bundles)
Windows registry Yes Yes Yes Yes Yes No
Windows service Yes Yes Yes Yes Yes Yes (basic)
Network devices Yes (SSH transport) Via device modules No Yes (network modules) Via proxy minions No
Kubernetes resources No Via puppetlabs-kubernetes No (use Habitat) Yes (k8s modules) No No
Cloud resources No Via cloud modules No Yes (300+ cloud modules) Via cloud modules No
LVM/RAID No Yes No Yes No No
Docker containers Yes (compose, container, image) Via puppetlabs-docker Via docker cookbook Yes (docker modules) Via dockerng No

Vigo registers 68 built-in resource types (agent/src/runner/mod.rs::build_executors, excluding the test-only mock) plus a user-supplied custom executor for 69 total, counting platform variants (reboot vs reboot_windows, etc.) once each as the operator writes them. Puppet has the deepest built-in resource coverage. Ansible has the widest (cloud, network, containers) through its module ecosystem. Vigo's custom executor JSON protocol allows extending coverage without modifying the agent binary.

Package management depth

Puppet's package resource is a benchmark — it supports 20+ providers (apt, yum, dnf, brew, chocolatey, pip, gem, npm, etc.), version pinning, holding, purging, install options, and source packages. Vigo's package executor handles 14 package managers — apt, dnf, yum, zypper, pacman, apk, brew, pkg, pkg_add, pkgin, IPS, Chocolatey, winget, and Scoop — with install/remove, exact version pinning, and allow_downgrade for safe version changes. Setting version: "1.4.9-1" ensures that exact version is installed on every convergence — if the package drifts (manual upgrade, apt upgrade), the agent corrects it within the next check-in interval. This is functionally equivalent to apt-mark hold for CM-managed systems, since the agent continuously enforces the desired version. The remaining gaps are source package installs and the long tail of provider-specific flags (e.g., --enablerepo, install_options).

Operational Characteristics

Bootstrap and enrollment

First-time agent setup Time to first convergence
Vigo curl | bash — one binary, generates keys, enrolls, starts service ~30 seconds
Puppet Install puppet-release package, install puppet-agent, configure server, sign cert ~5 minutes
Chef Download omnibus installer, configure client.rb, bootstrap with knife ~3 minutes
Ansible Install SSH key on target (or use password) Immediate (push)
Salt Install salt-minion package, configure master, accept key ~2 minutes
CFEngine Install cfengine-community package, bootstrap to hub ~1 minute

Vigo and CFEngine have the fastest bootstrap. Puppet's certificate signing workflow is the most involved.

Observability

Built-in metrics Compliance tracking Web UI Event webhooks
Vigo Prometheus — ~80 metrics on /metrics (documented in the monitoring setup guide; more time series at runtime via labels) Per-envoy status, sparklines, SIEM/CMDB export HTMX dashboard + security posture + admin section Yes (HMAC-signed)
Puppet Via PuppetDB queries Puppet Enterprise reports Puppet Enterprise Console Via report processors
Chef Via Chef Automate Chef Automate compliance Chef Automate UI Via handlers
Ansible Via Tower/AWX Tower compliance reports Tower/AWX UI Via callback plugins
Salt Via Salt Enterprise Via Salt Enterprise Salt Enterprise UI Via returners/reactors
CFEngine Mission Portal metrics Mission Portal compliance Mission Portal Via custom reports

The open-source versions of Puppet, Chef, Salt, and CFEngine have limited or no web UI — their dashboards are part of the commercial/enterprise products. Vigo's web UI, compliance tracking, and admin section are included in the base product.

When to Choose Vigo

  • Free for up to 100 nodes — all features, no time limit, no credit card
  • When you value simplicity — YAML configs anyone can read, one server, one binary, one publish command. No DSL to learn — not true of Puppet manifests, Chef recipes, or CFEngine promises
  • When you value security — mTLS everywhere, ED25519 per-request signing on every payload (uncommon among CM tools — Chef signs requests with RSA; Puppet and the others rely on transport-level certificates only), and a first-class secret: resolver that never lets secrets touch config files, databases, logs, or wire payloads
  • When you value ease of operation — single process, embedded SQLite, bootstrap in 30 seconds with a single curl command. No package manager, no runtime dependencies, no external database
  • When you value performance — the per-check-in path's dominant cost is a ~53 µs ED25519 verify (benchmarked); everything else on the cache-hit path totals under a microsecond; zero database queries on the hot path (the state write is batched and asynchronous). The server was load-tested end to end on an 8 vCPU / 32 GB host; the single-host ceiling depends on cadence — CPU-bound at a 1-second cadence (~7,450 on 8 vCPU), memory-bound at a relaxed one (~30,000 on a 32 GB host, ~623 KB all-in per envoy) — see the sizing analysis
  • When you need continuous enforcement — every resource is idempotent and re-evaluated every check-in. At 15-second intervals, drift is corrected before anyone notices it happened. This enables provable continuous compliance, self-healing infrastructure, and sub-minute incident response — capabilities that require 5-30 minute intervals with any other tool
  • When you need scalability — no compile masters, no database clusters, no worker pools; the spanner hub-spoke topology adds horizontal scale on top. (Single-host ceiling measured on an 8 vCPU / 32 GB host: ~7,450 envoys at a 1-second cadence (CPU-bound), ~30,000 at a relaxed 30–60s cadence (memory-bound); scales ~linearly with cores and RAM.)
  • When agent footprint matters — ~8 MiB static musl binary (x86_64; ~6 MiB on arm64) vs 50–200 MB for Ruby/Python-based agents. Deploys anywhere — edge, IoT, containers, resource-constrained hosts
  • When you need offline resilience — signed policy bundles with local convergence and results queuing for air-gapped, shipboard, or unreliable network environments. Most complete offline story of any agent-based CM tool