#Where Anvil Runs
Anvil runs on our infrastructure by default — Anvil Cloud — and you can also run it on yours. This page is the decision, and what each path actually looks like.
#1. Which one you want, in 60 seconds
#2. Anvil Cloud — what everyone uses today
The default. Zero setup, zero infrastructure, running the moment anvil protect completed.
Two hosts, two jobs. Your guarded calls dispatch to the money-path API at api.anvilcontrol.ai — that is what the SDK talks to on every call. The control plane is the dashboard at app.anvilcontrol.ai — or your own at http://localhost:7446/app when you're running one yourself with anvil serve — which walks to the next free port when 7446 is taken, and anvil open follows it there. Same code path, same behavior, same audit log format. anvil open picks whichever one you're actually on: your account's hosted workspace once this machine is paired, a local plane when one is already serving and you aren't.
| Anvil Cloud owns | You own |
|---|---|
| Uptime, backups, patches, cert rotation | The safe.wrap / wrap call in your code |
| Managed Postgres + Redis for dedup & durability | The .env anvil protect wrote |
| Dashboard rendering, decision-log streaming | Which mode each action runs in |
| Tamper-evident audit chain — on for every workspace, no switch to find | Rules you author in Policy Studio |
One workspace per verified email. Your API keys, your policies, your ledger, and your receipts are scoped to your workspace and stamped with it on write. A key reaches exactly one workspace's money path, and anvil audit and anvil verify read exactly that workspace's records. Tenancy is enforced at the query, not by convention — so "could another tenant's traffic show up in my log?" has a structural answer, not a policy one.
When we're down. An enforcing call is held, not quietly let through — ANVIL_FAIL_MODE defaults to closed, so the SDK raises rather than run a call it could not check. An action Anvil has already resolved to ghost keeps executing straight through an outage; that is ghost's contract and it holds even when we are unreachable. If you would rather have availability than that guarantee, graceful holds only money-moving calls above a threshold and open passes everything through — the same lever a self-hosted deployment pulls, and the same one you own either way. Fail-modes in full.
Custom rules still work here. Anvil Cloud evaluates all fifteen runtime primitives; your custom-code rules are the one thing it never runs — running your TypeScript inside a multi-tenant money service isn't a trade we'll make. Instead the SDK runs them in your process, before it calls us, from the files already in your repo. Same engine, same fail-closed behavior, and your rule code never leaves your machine. See Custom-code rules.
Cost. Free during beta — every tier, no paywall, no card. Paid tiers come later; pricing is the current state. Signup is gated today — you need a beta passcode, anvil protect <action> --invite <code>; email henry@anvilcontrol.ai if you don't have one.
What Anvil Cloud can't do today.
- Data physically staying inside your perimeter.
- Air-gapped deployments (no outbound network).
- Signed SLA with penalties.
Those are all reasons to look at §3.
Switching to self-host later. One env var: point ANVIL_API_BASE_URL at your instance. No code change. See "Switching between the two" in §3.
#3. Self-hosted — real, but early
#Why teams want it
- Data residency. Rules and audit records stay in your infrastructure. Nothing leaves.
- Air-gapped. No outbound network required at runtime.
- Trust posture. You keep custody of the audit chain.
anvil verifystill works. - Latency. The control-plane round-trip is co-located with your app.
#What you'd actually run
Two servers and two stores. The SDK talks to your money-path API the same way it talks to Anvil Cloud.
- Money-path API server —
src/api-server.ts. This is whatANVIL_API_BASE_URLpoints at:/v1/guard,/v1/complete,/v1/modes,/v1/resolve,/v1/keys. - Dashboard / Policy Studio control plane —
scripts/policy-import-server.mjs. The UI, the decision log, the approvals queue. - Postgres — not deferred and not optional: the money-path API server checks for a connection string at startup and exits without one, printing "A Postgres URL is required." Apply the schema with
anvil db migrate, which reads./migrationsrelative to your working directory — so run it from a checkout of the Anvil repo, not from your own app. - Redis — required at boot on both servers, not only for enforce, but with different gates. The money-path API pings Redis at startup and exits in every environment if it can't reach it. The control plane refuses only in production, where a memory-backed session store would be a security problem rather than an inconvenience.
- One env var —
ANVIL_API_BASE_URL=https://your.control.planein your app's environment.
The address you publish has to be reachable by your clients. In production Anvil refuses to hand a client an API base it could never call — a private or link-local address embedded in a pairing token or written into a developer's .env produces a setup that looks complete and fails at the first guarded call. If your plane sits behind private networking, set ANVIL_API_BASE_URL to the public origin your apps and laptops actually resolve, and confirm it with anvil doctor --deploy. A LAN address is fine when the LAN is genuinely where your clients live. Confirm it rather than assuming: anvil doctor --deploy --api-url https://your.api --control-url https://your.dashboard runs the topology preflight against the origins you just published, and tells you which one a client cannot resolve.
That Redis refusal is deliberate: session, OAuth-state, invite, and replay-nonce stores would otherwise fall back to process-local memory, and across replicas a replay nonce becomes single-use per replica rather than per token. Anvil refuses before it serves one request, so Redis is a prerequisite rather than a later step.
The control-plane script ships in the npm package; the migrations don't — we hand those to you as part of the engagement. That, plus the operational surface (auth, upgrades, backups, monitoring), is why the deploy guide isn't self-serve yet.
#What you own on the self-host path
Everything Anvil Cloud handles on the hosted path is now yours:
- Uptime, backups, patches, cert rotation for the control plane
- Postgres backups — we hand you our runbook as part of the engagement. Read the restore grace window section before you ever need a restore; it is the step nobody thinks about until it is too late.
- Redis availability and monitoring
- Perimeter / auth around the control plane (
ANVIL_CONTROL_TOKEN) - The audit chain and its signing key, if you use tamper-evident receipts
#Switching between the two
- Hosted → self-hosted. Stand up your own control plane, migrate the Postgres state, flip
ANVIL_API_BASE_URLin your app. Parallel-running the two during the cutover is supported. - Self-hosted → hosted. Flip the env var back; we import your state.
- Honest note: nobody's done either migration yet. You'd be first. Which is fine — we'll do it with you.
#Talk to us
The self-hosted path is a design-partner offer today:
- Direct partnership with the team building Anvil.
- Deployment shape fits your infrastructure — Kubernetes, VM, bare metal, whatever you already run.
- Early access to enterprise features as they land.
- Design-partner pricing.
Email henry@anvilcontrol.ai.