Windmill Labs
Windmill
 OSS Migration guide

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.

In short
  • 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.

vRO action (JavaScript)
com.corp.vm/getPoweredOffVms
// 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;
Windmill script (TypeScript)
f/infra/powered_off_vms.ts
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.

The same action with PowerCLI
f/infra/powered_off_vms_powercli.ps1
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 -AsArray

What 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.

Moves to Windmill
  • · vRO workflows
  • · Actions (JavaScript, Python, PowerShell)
  • · Configuration elements and SecureStrings
  • · Scheduled workflows (policies)
  • · Event broker subscriptions
  • · Approvals
  • · Packages, as a Git repository
Decide
  • · Request catalog: Windmill forms and apps, or keep it in ServiceNow
  • · Deployment inventory: Terraform or OpenTofu state, CMDB or NetBox
Stays where it is
  • · 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 estateExamplesVerdict
Workflow enginevRO workflows, actions, scheduled workflowsReplace with Windmill flows, scripts and schedules
Request intakevRA catalog, custom forms, approval policiesReplace with generated forms and approval steps, or integrate the ITSM catalog
EventsEvent broker subscriptions, vCenter alarms, monitoring alertsReplace subscriptions with triggers; integrate the sources
Execution toolsTerraform / OpenTofu, Ansible, PowerCLI, govcKeep, called from flow steps
Records of truthCMDB, IPAM, DNS, NetBoxIntegrate: read before provisioning, update after
PlatformvSphere, NSX, Kubernetes, public cloudsKeep

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

  1. 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.
  2. 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.
  3. How hard is it to leave? Prefer definitions in mainstream languages, stored as files you own.
  4. 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.
CapabilityAnsible / AWXOpenTofu / TerraformRundeckTemporalWindmill
Primary jobConfigure hostsDeclare resourcesRun ops jobsDurable app logicOrchestrate scripts and tools
Replaces the vRO enginePartialPartialPartial
Starts without a human (schedules, webhooks, queues)PartialPartialPartial
Approval steps inside a runPartialPartialPartial
Request forms generated from inputs
Python, PowerShell, TypeScript, Bash stepsPartialPartial
Definitions as files in GitPartial
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 / vRAWindmillEdition
WorkflowFlowAll
Action (JavaScript)TypeScript script. Plain logic ports with few changes; System.log becomes console.log, plugin calls become API or SDK callsAll
Scriptable task in Python, PowerShell or Node.jsScript in the same languageAll
Configuration elementResourceAll
SecureStringSecret variable; Vault, Azure Key Vault or AWS Secrets Manager backendsAll; external backends on Enterprise
Resource elementPlain-text file resource or S3 objectAll
Scheduled workflow / policyScheduleAll
Event broker subscriptionTrigger (webhook, HTTP route, Postgres, MQTT, Kafka, NATS, SQS...) with a preprocessorWebhooks and HTTP routes in all; Kafka, NATS, SQS, GCP Pub/Sub on Enterprise
User interaction / approval policyApproval stepAll; forms and approver restrictions on Cloud and Enterprise
Catalog item and custom formGenerated form or an appAll
Folders and permissionsFolders and groupsAll
Package exportCLI sync and Git syncCLI in all; Git sync on Cloud and Enterprise, or Community Edition up to 2 users
Tenants / business groupsWorkspacesUp to 3 workspaces on Community Edition
Remote execution near the targetWorker tags, agent workersTags in all; agent workers on Enterprise
PowerShell host on WindowsNative Windows workersEnterprise

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.

f/infra/provision_vm
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.

windmill-labs/windmill-vmware-vra-replacement

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.

  1. 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.
  2. 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.
  3. Merge. Near-duplicates that differ by a hard-coded cluster or network become one flow with an input.
  4. Collapse wrappers. A workflow that only calls one plugin action becomes one script.
  5. 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

  1. Export the vRO content and run vro_inventory.py on it, to get a range instead of a guess.
  2. Self-host Windmill with Docker Compose, push the example repository, and run the flows in dry run.
  3. Rebuild two or three real workflows end to end, including one triggered by an event, and time it.
  4. 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.

Rebuild your first catalog item

Clone the example repository, push it to a self-hosted Windmill, and run the provisioning flow in dry run.