v0.3.0 pre-1.0 · interfaces still moving
Ansible playbooks,
without the Python.
Parallax is a single Go binary that runs the playbooks, inventories and vaults you already have. Nothing to install on the targets — modules are compiled and shipped as static binaries.
go install go.digitalxero.dev/parallax/cmd/parallax@latest
PLAY [Configure web servers] ***************************************************
TASK [Gathering Facts] *********************************************************
ok: [web1]
ok: [web2]
TASK [Ensure document root exists] *********************************************
changed: [web1]
changed: [web2]
TASK [Render the index page] ***************************************************
changed: [web1]
changed: [web2]
TASK [Check the page is readable] **********************************************
ok: [web2]
ok: [web1]
PLAY RECAP *********************************************************************
web1 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0Verbatim output of
site/transcripts/play.yml,
re-recorded by task site:capture.
How it works
- 01
Your playbook is parsed as-is
The same YAML, the same inventory files, the same vault. Parallax reads Ansible's formats directly — there is no conversion step and no separate project file to maintain.
- 02
Each module is compiled to a static binary
A task's module is built once for the target's OS and architecture, then cached on the controller. Subsequent runs reuse the cached binary instead of rebuilding it.
- 03
The binary is shipped over the existing connection and run
It is copied over SSH, executed, and removed. The target needs a shell and nothing else — no Python interpreter, no pip packages, no long-lived agent to install, patch or monitor.
Connections are pooled and reused across tasks. Architecture →
What we've actually measured
Parallax compiles each module to a static binary once and caches it. A warm cache read costs about 3.6 µs; the write that populates it costs about 630 µs for a 1 MB binary. Against the benchmark's modelled 100 ms compile, that makes a cache hit roughly four orders of magnitude cheaper than rebuilding.
Scope: this is a synthetic Go benchmark using mock 1 MB binaries and a simulated 100 ms compile. It compares Parallax's cache to Parallax's own compiler. It is not a comparison against Ansible, and it does not measure a real playbook run. Methodology and full results.
Not measured yet: we have no published end-to-end benchmark of Parallax against Ansible on the same playbook and host count, and no template rendering benchmark. Until those exist we would rather show you one number we can defend than three we cannot.
How it compares
Where Parallax wins, where it matches, and where Ansible is still the better tool.
| Capability | Ansible | Parallax |
|---|---|---|
| Controller runtime (Parallax ahead) | Python 3.x plus pip-installed dependencies | One static binary |
| Target requirements (Parallax ahead) | A Python interpreter on every managed host | None — modules ship as compiled binaries |
| Playbooks, inventory, vault (equivalent) | YAML, INI/YAML inventory, AES256 vault (1.1 & 1.2) | Same formats, read directly |
| Templating (mostly compatible, with caveats) | Jinja2 | gonja — Jinja2-compatible, not byte-identical |
| Connection types (mostly compatible, with caveats) | Large plugin ecosystem | ssh, local, docker, winrm |
| Handlers (equivalent) | Notified at end of play, or now with meta: flush_handlers | Same, including mid-play flush |
| Module library (Ansible ahead) | Thousands, via Galaxy collections | 134 built in |
| Role & collection distribution (Ansible ahead) | ansible-galaxy install | Vendor roles yourself; no Galaxy client |
| Custom modules and plugins (Ansible ahead) | Write in Python | Write in Go; existing Python plugins must be ported |
| Maturity (Ansible ahead) | Stable, over a decade of production use | v0.3.0, pre-1.0 |
What Parallax doesn't do yet
Read this before you plan a migration. These are the things that will stop a real playbook, not hypotheticals.
- Unsupported modules fail the play
- There is no Python fallback. A task using a module outside the
134 built in — anything from
community.docker,kubernetes.core,amazon.awsand most other collections — fails with couldn't resolve module/action. Check your playbooks against the module reference first. - No Galaxy client
- There is no
ansible-galaxyequivalent. Roles are read from disk, so anything you depend on has to be vendored into your repository or installed out of band.galaxy_infoin role metadata is parsed but not acted on. - Python plugins must be ported
- Custom modules, filters, lookups, callbacks and connection plugins are Go. Parallax loads them over go-plugin RPC; it cannot execute your existing Python ones. See the plugin porting guide.
- Templating is compatible, not identical
- gonja implements Jinja2 but is a separate engine. Common filters and control flow behave the same; unusual whitespace control, obscure filters and Python-specific expressions inside templates may not.
- Pre-1.0
- v0.3.0. The module SDK interfaces are still changing, so out-of-tree plugins may need updating between releases.
Try it
The playbook below is the one recorded at the top of this page. Both hosts use the local connection, so it runs on your machine with nothing else set up.
Install
go install go.digitalxero.dev/parallax/cmd/parallax@latestSave an inventory and a playbook
inventory.ini [web] web1 ansible_connection=local web2 ansible_connection=localplay.yml - name: Configure web servers hosts: web gather_facts: true vars: docroot: /tmp/parallax-demo/www tasks: - name: Ensure document root exists file: path: "{{ docroot }}/{{ inventory_hostname }}" state: directory mode: "0755" - name: Render the index page copy: dest: "{{ docroot }}/{{ inventory_hostname }}/index.html" content: "hello from {{ inventory_hostname }}\n" mode: "0644" - name: Check the page is readable stat: path: "{{ docroot }}/{{ inventory_hostname }}/index.html"Run it
parallax play -i inventory.ini play.yml