Blazing fast Azure CLI, written in Rust.
raz reimplements a slice of the Azure CLI (az) in Rust, invoked as raz. It mirrors az's
command-module design and ships two front-ends over one core library:
raz— a minimal CLI (raz login,raz logout,raz account …,raz vnet …,raz vm …).raz-tui— an interactive ratatui + tachyonfx dashboard that browses subscriptions, VMs, and VNets with animated view transitions, plus a:command palette with autocomplete that runs any raz command and shows its output.
raz is a single native binary; az is a Python application that re-initializes its
interpreter and imports a large module tree on every invocation.
Median of 7 runs, Windows 10, az 2.85.0 vs raz 0.1.0 (release build), output discarded:
| Command | raz | az | Speed-up |
|---|---|---|---|
--version |
9 ms | 363 ms | ~40× |
--help |
9 ms | 264 ms | ~29× |
account list (local cache) |
12 ms | 473 ms | ~39× |
raz wins decisively wherever the CLI engine itself is the cost.
For commands that call Azure Resource Manager (group/vnet/vm list, create, …), wall
time is dominated by the network. raz currently mints a fresh access token via a
refresh-token exchange on every ARM command (an extra Entra round-trip), so a *-list
lands around ~1.3 s and the startup advantage is offset; az reuses a cached MSAL token and
skips that hop. Caching the per-tenant token in ~/.raz (which already stores expires_on)
is the planned fix — until then, raz's real edge is the overhead numbers above, not live ARM
latency. A clean head-to-head on identical subscriptions wasn't possible on the test machine
(az and raz were signed in to different tenants).
-o table/json/tsv formatting matches az. Content differs by design — raz returns minimal,
near-raw ARM JSON; az returns curated camelCase objects with more convenience fields:
account show |
keys returned |
|---|---|
| raz | id, name, tenant_id, is_default |
| az | id, name, tenantId, isDefault, state, user, homeTenantId, managedByTenants, environmentName |
| Capability | raz | az |
|---|---|---|
| login/logout · account · group | ✓ | ✓ |
vnet/vm list·show·create·update·delete |
✓ | ✓ |
| resource-provider auto-register on create | ✓ | ✓ |
vm start/stop/restart/deallocate |
✓ | ✓ |
| everything else (storage, aks, role, keyvault, …) | — | ✓ (full) |
raz implements a deliberate slice; az remains the full product.
crates/
raz-core/ # engine: context, config, auth (device-code), ARM client, output
raz/ # minimal CLI front-end (clap)
raz-tui/ # ratatui + tachyonfx dashboard front-end
raz-core modules map onto how az structures a command module:
| az | raz-core |
|---|---|
command table (commands.py) |
clap subcommand tree + command::Command trait |
load_arguments / _params.py |
clap #[derive(Args/Subcommand)] |
custom.py |
arm::vm / arm::vnet / auth + front-end command fns |
_format.py table transformers |
output::{render, TableSpec} |
global --subscription/--output/--query |
context::GlobalArgs |
~/.azure profile |
config::Profile (~/.raz/profile.json) |
- Live:
login(OAuth device-code flow against Entra, with az-style cross-tenant subscription discovery),logout,account(list/show/set/list-tenants),group(create/list/show/delete),vnet/vmlist+show(ARM GETs), andvnet/vmcreate/update/delete— real ARM PUT/DELETE with long-running-operation polling. New resources default to West Europe;vm createpre-flights VM-size availability for the region (failing fast with a clear message before creating anything) and auto-provisions the resource group, virtual network/subnet, and NIC it needs. - Resource-provider auto-registration. On the first
vnet/vm createin a fresh subscription, raz registersMicrosoft.Network/Microsoft.Computeand waits for them (just likeazdoes silently), so create "just works". - VM power actions:
vmstart/stop/restart/deallocate— real ARM POST actions with operation polling. - HTTP uses
reqwest. A production port would backarm::clientand the token credential withazure_core(Pipeline+BearerTokenPolicy) andazure_identity; theauth::credential::TokenSourceandarm::clientseams are shaped for that swap.
The repository root is the Cargo workspace:
cargo build --release
cargo test
cargo clippy --all-targetsraz login # device-code prompt; discovers tenants + subscriptions
raz account list -o table # all subscriptions across tenants
raz account set -s <id|name> # set the active subscription (persisted to ~/.raz)
raz account list-tenants # distinct tenants
raz vm list -o table # VMs in the active subscription
raz vnet list -o table # virtual networks
raz vm show -g <rg> -n <name> # single VM as JSON
raz -s <id|name> vm list # override subscription for one command
raz --query "0.name" vm list # minimal dotted-path projection
# Resource groups
raz group create -n <rg> # defaults to West Europe
raz group list -o table
raz group delete -n <rg> --yes # cascades to all resources in it
# Create / update / delete (default region: West Europe)
raz vnet create -g <rg> -n <vnet> # 10.0.0.0/16 + default subnet
raz vnet update -g <rg> -n <vnet> --tag env=dev --add-prefix 10.1.0.0/16
raz vnet delete -g <rg> -n <vnet>
raz vm create -g <rg> -n <vm> --ssh-key-value "$(cat ~/.ssh/id_rsa.pub)"
raz vm update -g <rg> -n <vm> --size Standard_B2s --tag owner=me
raz vm delete -g <rg> -n <vm>
raz logout # clears ~/.raz
raz-tui # interactive dashboard (q/Esc to quit)Exit codes follow az: 0 success, 1 generic/auth error, 2 usage, 3 resource not found.
GitFlow with git-driven semantic versioning via the reusable
KarlesP/cadence workflow. The root VERSION file is
the source of truth; main/release/*/hotfix/* produce tags + GitHub Releases.
See .github/workflows/.
Two manual (workflow_dispatch) workflows build the binaries for Linux and Windows:
- Build (debug) — debug binaries uploaded as artifacts.
- Build (release) — optimized binaries uploaded as artifacts and attached to a GitHub
Release tagged from
VERSION.
Why use raz instead of az?
az is a large Python application — a cold start pays for the interpreter, dozens of imports,
and a sprawling extension system before it does anything. raz is a single native binary: it
starts in milliseconds, has no runtime to install, and ships as one file you can drop on a box
or into a container scratch image. For the commands it covers, it does the same ARM/Entra calls
with a fraction of the overhead.
Is raz a drop-in replacement for az?
No. raz intentionally implements a slice of az (login/logout, account, and vnet/vm
list/show) to demonstrate the architecture. Mutating operations are stubbed. Use az for full
coverage; use raz where startup time, footprint, or a single-binary deployment matters.
How does login work without an app registration?
raz login uses the OAuth 2.0 device-code flow against Microsoft Entra with the well-known
public Azure CLI client id — the same approach az uses — then discovers subscriptions across
every tenant your identity can reach via silent refresh-token exchange.
Does it talk to real Azure?
Yes. login, account, and vnet/vm list/show make live ARM REST calls. Tokens and the
active subscription are cached under ~/.raz.
Why is it "blazing fast"?
Native compiled Rust, no interpreter startup, minimal dependencies, and direct reqwest calls
to ARM rather than a layered SDK + plugin system.
Created and maintained by KarlesP.