Open source alternative to VMware vRA and vRO
VCF Automation (formerly Aria Automation and vRealize Automation, vRA) and vRealize Orchestrator (vRO) are, for most teams, an automation engine: workflows, scheduled jobs, event-driven runs and request approvals. An open source alternative takes over that engine. It does not replace vSphere. The hypervisor, Terraform modules, Ansible roles and ServiceNow stay, and the new workflows call them.
This guide shows what a vRO action looks like once it moves to Windmill, what moves and what stays, how vRO objects map, and how to size the work before the renewal date with an open source inventory script.
- Replace the vRO engine. Keep vSphere and the tools vRO called.
- Decide where the request catalog and the deployment inventory live.
- Inventory the vRO content first: a large part of most estates is unused or a thin wrapper.
- Plan backward from the license renewal date, since that is when the savings start.
A vRO action, before and after
Most of a vRO estate is actions like this one: find VMs by name prefix and keep the powered-off ones. In Windmill it becomes a TypeScript script. The vCenter plugin object turns into a call to the vSphere Automation REST API, the configuration element turns into a vmware_vsphere resource picked in the generated form, and the result is plain JSON that the next step of a flow can use.
// Inputs: prefix (string)
// Return type: Array/VC:VirtualMachine
var vms = VcPlugin.getAllVirtualMachines(null,
"xpath:name[starts-with(.,'" + prefix + "')]");
var result = [];
for (var i in vms) {
if (vms[i].runtime.powerState.value == "poweredOff") {
result.push(vms[i]);
}
}
System.log("Found " + result.length + " powered-off VMs");
return result;
type VmwareVsphere = { server: string; username: string; password: string };
export async function main(vsphere: VmwareVsphere, prefix = "") {
const base = `https://${vsphere.server}/api`;
const token = await (await fetch(`${base}/session`, {
method: "POST",
headers: { Authorization: "Basic " +
btoa(`${vsphere.username}:${vsphere.password}`) },
})).json();
const vms = await (await fetch(
`${base}/vcenter/vm?power_states=POWERED_OFF`,
{ headers: { "vmware-api-session-id": token } },
)).json();
const result = vms.filter((vm) => vm.name.startsWith(prefix));
console.log(`Found ${result.length} powered-off VMs`);
return result;
}The logic carries over line for line; the plugin calls are what you rewrite. Both versions are in the example repository, with error handling and session cleanup.
PowerShell and PowerCLI keep working
Many vRO estates run PowerShell through a PowerShell host or PowerCLI actions. In Windmill, PowerShell is a script language like any other: parameters become the input form, and Import-Module installs the module from the PowerShell Gallery on the first run, then caches it. PowerCLI runs on Linux workers with PowerShell 7, and on native Windows workers (Enterprise) when a script needs a domain-joined host.
param([PSCustomObject]$Vsphere, [string]$Prefix = "")
Import-Module VMware.VimAutomation.Core # installed from PSGallery on first run
$cred = New-Object PSCredential($Vsphere.username,
(ConvertTo-SecureString $Vsphere.password -AsPlainText -Force))
$server = Connect-VIServer -Server $Vsphere.server -Credential $cred
Get-VM -Server $server -Name "$Prefix*" |
Where-Object { $_.PowerState -eq 'PoweredOff' } |
Select-Object Name, NumCpu, MemoryGB |
ConvertTo-Json -AsArrayWhat moves, what you decide, what stays
vRA bundles three things: a request catalog with forms and approval policies, a deployment inventory that tracks what each request created, and vRO, the workflow engine that does the work. Only the engine has to move.
- · vRO workflows
- · Actions (JavaScript, Python, PowerShell)
- · Configuration elements and SecureStrings
- · Scheduled workflows (policies)
- · Event broker subscriptions
- · Approvals
- · Packages, as a Git repository
- · Request catalog: Windmill forms and apps, or keep it in ServiceNow
- · Deployment inventory: Terraform or OpenTofu state, CMDB or NetBox
- · vSphere, vCenter, NSX
- · Public clouds and Kubernetes
- · Terraform / OpenTofu modules
- · Ansible roles
- · ServiceNow, CMDB, IPAM, DNS
- · Secret managers and monitoring
Split the estate by function and give each part a verdict. "Keep" means Windmill calls the tool and reads its result. "Integrate" means the tool also starts flows by sending events.
| Part of the estate | Examples | Verdict |
|---|---|---|
| Workflow engine | vRO workflows, actions, scheduled workflows | Replace with Windmill flows, scripts and schedules |
| Request intake | vRA catalog, custom forms, approval policies | Replace with generated forms and approval steps, or integrate the ITSM catalog |
| Events | Event broker subscriptions, vCenter alarms, monitoring alerts | Replace subscriptions with triggers; integrate the sources |
| Execution tools | Terraform / OpenTofu, Ansible, PowerCLI, govc | Keep, called from flow steps |
| Records of truth | CMDB, IPAM, DNS, NetBox | Integrate: read before provisioning, update after |
| Platform | vSphere, NSX, Kubernetes, public clouds | Keep |
Why teams look for an open source option
Licensing follows the hypervisor. Aria Automation is sold only as a component of VMware Cloud Foundation (VMware datasheet), so the automation bill tracks the cores of the whole VCF estate rather than how much automation runs.
The roadmap narrows to private cloud. VCF Automation 9.1.1 disables native public cloud endpoints by default, with full removal planned for the next major release (Broadcom KB 448993). AWS, Azure and GCP automation that ran through vRA becomes code a team maintains either way.
Leaving should not mean rewriting twice. vRO content lives in its database and exports as packages. In Windmill, scripts and flows are plain files (TypeScript, Python, PowerShell, YAML) in a Git repository, on an AGPLv3 core you can self-host without a license.
Four questions for any vRA replacement
- Does it replace the engine, or a tool the engine called? Terraform and Ansible were never what vRO replaced: vRO called them. Swapping vRO for one of them moves the orchestration into CI pipelines and wrapper scripts.
- Can it start without a human? Half of a vRO estate runs on schedules and event subscriptions. The replacement needs schedules, webhooks and message queue triggers, not only a run button.
- How hard is it to leave? Prefer definitions in mainstream languages, stored as files you own.
- Who else will use it? If data, platform and application teams can run their jobs on the same platform, the cost of the migration is shared.
| Capability | Ansible / AWX | OpenTofu / Terraform | Rundeck | Temporal | Windmill |
|---|---|---|---|---|---|
| Primary job | Configure hosts | Declare resources | Run ops jobs | Durable app logic | Orchestrate scripts and tools |
| Replaces the vRO engine | Partial | Partial | Partial | ||
| Starts without a human (schedules, webhooks, queues) | Partial | Partial | Partial | ||
| Approval steps inside a run | Partial | Partial | Partial | ||
| Request forms generated from inputs | |||||
| Python, PowerShell, TypeScript, Bash steps | Partial | Partial | |||
| Definitions as files in Git | Partial | ||||
| Self-hosted, open source core |
This table is our reading of each tool's documentation as of November 2026, and we are not neutral: we build Windmill. "Partial" means the capability exists with significant constraints, such as AWX approvals living only in workflow templates, or Temporal needing the schedule, signal and form layers written in application code. Keep Ansible and Terraform or OpenTofu for the jobs they already do, and use Temporal for long-running logic inside your own applications. For the orchestration layer vRO provided, compare Windmill with the tools above in the alternatives overview. If a cell is wrong, open an issue.
How vRO objects map to Windmill
Most vRO objects have a direct counterpart. The one that does not is the vCenter plugin: Windmill has no proprietary vSphere step, so calls through plugin objects such as VC:VirtualMachine become calls through the vSphere provider for OpenTofu, pyvmomi, govmomi or PowerCLI.
| vRO / vRA | Windmill | Edition |
|---|---|---|
| Workflow | Flow | All |
| Action (JavaScript) | TypeScript script. Plain logic ports with few changes; System.log becomes console.log, plugin calls become API or SDK calls | All |
| Scriptable task in Python, PowerShell or Node.js | Script in the same language | All |
| Configuration element | Resource | All |
| SecureString | Secret variable; Vault, Azure Key Vault or AWS Secrets Manager backends | All; external backends on Enterprise |
| Resource element | Plain-text file resource or S3 object | All |
| Scheduled workflow / policy | Schedule | All |
| Event broker subscription | Trigger (webhook, HTTP route, Postgres, MQTT, Kafka, NATS, SQS...) with a preprocessor | Webhooks and HTTP routes in all; Kafka, NATS, SQS, GCP Pub/Sub on Enterprise |
| User interaction / approval policy | Approval step | All; forms and approver restrictions on Cloud and Enterprise |
| Catalog item and custom form | Generated form or an app | All |
| Folders and permissions | Folders and groups | All |
| Package export | CLI sync and Git sync | CLI in all; Git sync on Cloud and Enterprise, or Community Edition up to 2 users |
| Tenants / business groups | Workspaces | Up to 3 workspaces on Community Edition |
| Remote execution near the target | Worker tags, agent workers | Tags in all; agent workers on Enterprise |
| PowerShell host on Windows | Native Windows workers | Enterprise |
A vRA catalog item rebuilt as a flow
The provision_vm flow is what a typical "Linux VM" catalog item, its approval policy and the vRO workflow behind it become. It takes a VM name, a size, an OS, an environment and an optional ServiceNow request number.
preprocessor ServiceNow request payload -> typed inputs (trigger runs only) plan size + OS -> CPU, RAM, disk, template; needs approval? approval suspends for prod or large requests, skipped otherwise provision OpenTofu clones the template on vSphere (state in Postgres) configure Ansible baseline over SSH close_ticket work note + Closed Complete on the RITM failure destroys a half-built VM, writes the error on the ticket
The form Windmill generates from the inputs is the catalog item. ServiceNow can stay the front door instead: a business rule calls the flow's webhook and the preprocessor maps the request. The deployment inventory is the OpenTofu state, one workspace per VM, which the decommission_vm flow destroys from.
The same repository has the Day 2 jobs that usually sit in vRO next to the catalog: rolling patching with a canary, a snapshot sweeper and a certificate expiry check, each with a schedule. Every flow has a dry_run input, so you can walk it before connecting vCenter.
Size the migration before you commit to it
Estimates built from the raw workflow count overshoot. Export the content first, then sort it. The vro_inventory.py script in the example repository does the sorting: point it at .package files or a Build Tools project and it labels every workflow and action retire, merge, wrapper, rebuild or convert, and lists the plugins you depend on. It uses only the Python standard library and runs where the export is, so nothing leaves your network.
- Export. Build Tools for VMware Aria pulls vRO packages into files you can read and diff. Use a read-only account on a non-production instance.
- Retire. Workflows with no runs in the past year, and old copies kept "just in case", do not migrate. Give the script a CSV of last run dates (
--runs) and it marks them. - Merge. Near-duplicates that differ by a hard-coded cluster or network become one flow with an input.
- Collapse wrappers. A workflow that only calls one plugin action becomes one script.
- Convert or rebuild. Actions with plain JavaScript logic convert to TypeScript. Workflows built around plugin objects are rebuilt on the vSphere API. Count integration libraries (ServiceNow, Infoblox, AD) separately: each is written once and shared.
Coding agents do much of the conversion well, because the target is ordinary code. The Windmill CLI installs skills that teach Claude Code and other agents how Windmill scripts and flows are written, so an agent can read an exported action and write the script, its schema and a dry-run path, for a person to review.
Savings start at the license renewal, not at cutover. Work the plan backward from the renewal notice deadline: which workflows must be off vRO by then, and which can wait for the next cycle.
Where to start
- Export the vRO content and run
vro_inventory.pyon it, to get a range instead of a guess. - Self-host Windmill with Docker Compose, push the example repository, and run the flows in dry run.
- Rebuild two or three real workflows end to end, including one triggered by an event, and time it.
- If you need agent workers in isolated segments, external secret backends, approval forms or longer audit retention, run an Enterprise trial alongside.
For the broader picture of what Windmill runs for infrastructure teams, see infrastructure automation.
Frequently asked questions
More you can build on Windmill
Infrastructure automation is one piece. The same platform runs data pipelines, internal apps, AI agents and Windows automation.
Write scripts in TypeScript, Python, Go, Bash, SQL and trigger them from webhooks, schedules, queues or the auto-generated UI.
Build production-grade internal apps with backend scripts, data tables and React, Vue or Svelte frontends.
Orchestrate ETL jobs with parallel branches, DuckDB queries and connections to any database or S3 bucket.
Build AI agents with tool-calling, DAG orchestration, sandboxes and direct access to your scripts and resources.
Chain scripts into flows with approval steps, parallel branches, loops and conditional logic.
Run cron jobs with a visual builder, execution history, error handlers, recovery handlers and alerting.
Run PowerShell, MSSQL with Kerberos and C# natively on domain-joined Windows servers, no Docker required.
Orchestrate OpenTofu, Ansible, approvals and ServiceNow requests on vSphere, Kubernetes and cloud, plus the Day 2 jobs.
Rebuild your first catalog item
Clone the example repository, push it to a self-hosted Windmill, and run the provisioning flow in dry run.