@anvil-works/anvil-cli
v0.8.1
Published
CLI tool for developing Anvil apps locally
Readme
anvil-cli
anvil-cli is the command-line tool for developing Anvil apps locally.
Use it to:
- check out an Anvil app into a local folder
- edit code in your own editor
- keep that local folder synced with Anvil while you work
- switch between local code editing and the Anvil designer in the same workflow
Install
macOS or Linux
curl -fsSL https://anvil.works/install-cli.sh | shWindows PowerShell
irm https://anvil.works/install-cli.ps1 | iexWindows CMD
curl -fsSL https://anvil.works/install-cli.cmd -o install.cmd && install.cmd && del install.cmdManual npm installation
This requires your own supported Node.js installation (22, 24 or 26 LTS).
npm install -g @anvil-works/anvil-cli@latestThe installers use an independently installed Node.js 22, 24 or 26 LTS when available. If Node is missing or unsupported, installation stops with setup instructions. There are no interactive prompts.
To allow the installer to provide a private Node.js 24 copy when needed, use the appropriate command below.
macOS/Linux:
curl -fsSL https://anvil.works/install-cli.sh | sh -s -- --install-nodePowerShell:
& ([scriptblock]::Create((irm https://anvil.works/install-cli.ps1))) -InstallNodeCMD:
curl -fsSL https://anvil.works/install-cli.cmd -o install.cmd && install.cmd --install-node && del install.cmdThe private copy is stored under ~/.anvil-cli and added to PATH, so other Node tools may use it too. Rerunning the installer updates that copy to the latest Node 24 release and migrates older bundled Node 20 installations.
Run anvil update to check for CLI and bundled Node updates. If bundled Node needs updating, it shows the installer command to rerun.
Quickstart
This is the main happy path:
- Install
anvil-cli. - Run
anvil configure. - Run
anvil checkout. - Change into the app directory.
- Run
anvil watch.
1. Configure the CLI
Run:
anvil configureThis guided setup helps you:
- set your default Anvil server URL
- choose a preferred editor, if you want one
- log in to Anvil
If you use anvil.works, you can usually accept the default server when prompted.
2. Check out your app
Run:
anvil checkoutThis opens an interactive app picker and creates the app directory for you.
If you already have the app URL from the Anvil editor, you can also run:
anvil checkout https://anvil.works/build/apps/W36XUTXGNPDK6VEA my-app
cd my-appYou can also check out by app ID:
anvil checkout W36XUTXGNPDK6VEA my-app --url anvil.works
cd my-app3. Start syncing
Inside the app directory, run:
anvil watchLeave this running while you work.
With anvil watch running:
- local code changes sync into Anvil
- compatible changes made in Anvil sync back into your local files
- you can keep using the Anvil designer when you need it
Core Commands
These are the commands that matter most for normal local development:
anvil configure
Guided setup for your default server URL, editor preference, and login.
anvil configureanvil checkout
Create a local app folder from an editor URL, Git URL, app ID, or interactive picker.
anvil checkout [input] [directory]
anvil co [input] [directory]Common examples:
anvil checkout
anvil checkout https://anvil.works/build/apps/W36XUTXGNPDK6VEA my-app
anvil checkout W36XUTXGNPDK6VEA my-app --url anvil.works
anvil co -Q "dashboard"Useful options:
-O, --openopen the app folder after checkout-b, --branch <BRANCH>check out a specific branch--git-url <GIT_URL>use a separate Git server-Q, --query <QUERY>prefill the interactive search-u, --url <ANVIL_URL>choose the Anvil installation explicitly-U, --user <USERNAME>choose the logged-in account explicitly-f, --forceoverride destination safety checks
anvil create
Create a blank Anvil app and check it out locally. Without a name, the CLI prompts for one. The server supplies current Python 3 runtime defaults.
anvil create "My App"
anvil create "My App" ./my-app --tag internal sales
anvil create "My App" --directory my-app --url anvil.works --user [email protected]
anvil create "My App" --no-checkout --tag internal salesUseful options:
-d, --directory <PATH>choose the local directory (defaults to the app name with spaces replaced by underscores)--no-checkoutcreate only the remote app and print its ID and editor URL--tag <TAG...>add space-separated tags or repeat the option; place after the name and destination-u, --url <ANVIL_URL>choose the Anvil installation-U, --user <USERNAME>choose the logged-in account--git-url <GIT_URL>use a separate Git server-O, --openopen the checkout after creation
App names need quotes when they contain spaces. Leading and trailing whitespace is removed; the remaining name is preserved. Supply the destination as the second argument or with --directory, but not both. The destination must be empty and outside an existing Git repository. These checks run before creating the remote app.
With --no-checkout, no local directory is created or checked. It cannot be combined with a destination argument, --directory, --git-url, or --open; these combinations fail before login or creation. JSON output includes the app ID, name, server, account, tags, and editorUrl, without checkout fields.
Tags are combined, trimmed, lowercased, and deduplicated. An app can have at most 20 unique tags, each containing 1 to 50 letters, digits, hyphens, or underscores.
Server and account selection follow checkout, including interactive selection and login when needed. In scripts, supply the name and use --url and --user when the selection is ambiguous. --json disables prompts.
If creation succeeds but checkout fails, the error identifies the created app and explains how to recover it. Do not rerun create, which would create another app. JSON errors include the created app details in data.created. Failure to open an editor after checkout produces a warning and preserves the successful result.
anvil watch
Keep your local app folder synced with Anvil while you work.
anvil watch [path]
anvil w [path]Common examples:
anvil watch
anvil watch -s
anvil watch -a
anvil watch -O
anvil watch --url anvil.company.comUseful options:
-A, --appid <APP_ID>specify the app directly-s, --staged-onlysync only staged files-a, --autohandle some branch and sync transitions automatically-O, --openopen the watched path in your preferred editor-u, --url <ANVIL_URL>choose the Anvil installation explicitly-U, --user <USERNAME>choose the logged-in account explicitly
anvil validate
Check an Anvil app file or directory before syncing, or when the CLI reports a validation error.
anvil validate <path>When given a file, the command chooses the validator from the file path. When given a directory, it recursively validates supported files under that directory. It supports:
anvil.yaml.yamlfiles underclient_code/, includingclient_code/**/form_template.yaml.htmlfiles underclient_code/, includingclient_code/**/form_template.htmland module-formclient_code/<Form>.html.cssfiles undertheme/assets/, includingtheme.css: warns about selectors targeting the removedanvil-dropzonewrappers. These warnings do not fail validation; general CSS syntax is not checked..pyfiles underclient_code/andserver_code/
Common examples:
anvil validate anvil.yaml
anvil validate client_code/Form1/form_template.yaml
anvil validate client_code/Form1.yaml
anvil validate client_code/Form1/form_template.html
anvil validate client_code/Form1.html
anvil validate client_code/Helpers.py
anvil validate server_code/ServerModule.py
anvil validate theme/assets/theme.css
anvil validate .HTML validation parses the template with @anvil-works/form-template-parser, checks optional YAML frontmatter, and reports semantic issues such as duplicate explicit component names or invalid component types.
Python validation in the anvil validate command uses the native checker bundled by @anvil-works/anvil-ty for semantic app checks when validating existing Python files. Set ANVIL_TY to an executable path to override the bundled checker. ANVIL_TY_TIMEOUT_MS sets its timeout in milliseconds (default: 300000), and ANVIL_API_STUBS_PATH selects an alternative Anvil API stub directory. The programmatic validatePath() API keeps a lightweight synchronous fallback that checks syntax using a local Python interpreter (ANVIL_PYTHON, uv, python3, or python) and performs basic form structure checks.
Validation never fetches dependencies. Apps with dependencies use the existing .anvil/deps cache; a missing, incomplete, or configuration-mismatched cache produces a non-fatal warning with instructions to run anvil deps fetch.
When the file is valid, the command prints a success message and exits with status 0. When the file is invalid, it prints path-specific validation issues and exits with a non-zero status.
Use --json with anvil validate to emit structured NDJSON output for scripts or LLM tooling.
anvil convert-template
Convert an Anvil form template YAML file to the HTML template format.
anvil convert-template client_code/Form1/form_template.yaml
anvil convert-template client_code/Form1.yamlBy default, the command writes the sibling .html file and removes the source .yaml file after the write succeeds:
client_code/Form1/form_template.yamlbecomesclient_code/Form1/form_template.htmlclient_code/Form1.yamlbecomesclient_code/Form1.html
Useful options:
-o, --output <path>write to a specific output path-f, --forceoverwrite an existing output file--keep-sourcekeep the source YAML file
Use --json with anvil convert-template to emit the source path, output path, and whether the source YAML was removed.
Conversion uses @anvil-works/form-template-parser. When package-qualified form specs such as form:MyForm or dependency item_template values are present, the command reads anvil.yaml (and .anvil/deps/manifest.json when needed) to canonicalize them before serializing HTML.
anvil test
Run your app's server tests (tests/server_tests) on Anvil, and print pytest's output as they run.
anvil test
anvil test tests/server_tests/test_orders.py::test_refund
anvil test -k "login and not slow"
anvil test --collect-onlyThe tests run on the commit you have checked out (HEAD), which must already be pushed to Anvil. If you have uncommitted changes, the command warns you that they aren't included.
Targets are paths or pytest node IDs in tests/server_tests, relative to the current directory. -k takes a pytest keyword expression.
The app, server and account are chosen as anvil watch chooses them, including asking you when there's a choice. In CI, use -A, --appid <APP_ID>, -u, --url <ANVIL_URL> and -U, --user <USERNAME> when the choice is ambiguous. --json disables prompts.
The command exits with pytest's exit code, for example 0 if every test passed and 1 if any failed, so you can use it in CI. If the run couldn't start or finish, for example because the server runtime failed to launch, it prints the error and exits 1. Press Ctrl-C to cancel the run.
Other useful commands
anvil login
anvil login anvil.company.com
anvil logout
anvil config list
anvil config get <key>
anvil config set <key> <value>
anvil config reset
anvil validate <file>
anvil convert-template <file>
anvil test
anvil version
anvil update
anvil --help
anvil <command> --helpGlobal options:
-V, --verboseshow detailed output--jsonoutput NDJSON for scripting or LLM tooling
Recommended Workflows
Work between your editor and the Anvil designer
The basic loop is:
- Run
anvil watchin your app folder. - Edit Python locally in your editor.
- Open the same app in Anvil when you need the designer.
- Keep
anvil watchrunning while you move between them.
Use branches by default
Create or switch to a branch before you start watching:
git checkout -b my-feature
anvil watchIf you switch branches while watching, anvil watch may prompt you to restart or resync. If you want the CLI to handle that automatically, use:
anvil watch --autoUse staged-only mode when experimenting
If you want tighter control over what syncs to Anvil, use:
anvil watch --staged-only
git add server_code/MyModule.pyOnly staged files will sync.
Work with AI assistants
A simple pattern is:
- Start
anvil watch. - Open the app folder in Cursor, VS Code, or another editor.
- Make or review AI-generated changes locally.
- Test the synced result in Anvil.
If you are iterating on messy changes, combine this with --staged-only.
Multiple Accounts and Enterprise Installs
Most users on anvil.works do not need to think about this.
If you work across multiple Anvil installations or multiple logged-in accounts, the CLI can usually infer the right choice. If it cannot, you can override it with:
--urlto choose the Anvil installation--userto choose the logged-in account
Examples:
anvil login anvil.company.com
anvil checkout APPID my-app --url anvil.company.com
anvil watch --url anvil.company.com --user [email protected]
anvil logout --url anvil.company.com --user [email protected]If you want to change the default server permanently:
anvil config set anvilUrl https://anvil.company.comWhen you run anvil login, the CLI now supports both local and headless flows:
- press
Enterto open the default browser - or copy the printed device-login URL and code to continue in a browser of your choice
For anvil login, prefer the positional server argument in docs and examples:
anvil login anvil.company.com--url is also supported if needed.
Troubleshooting
anvil command not found
Try the install command again, then open a new terminal and run:
anvil --helpIf the install script fails, use the npm fallback.
Login or account selection problems
Try:
anvil login
anvil config listIf you use a self-hosted installation:
anvil login anvil.company.comanvil checkout cannot find the app
Try using the app URL directly from the Anvil editor, or pass --url and --user if the CLI is looking at the wrong installation or account.
Local changes are not appearing in Anvil
Make sure you are in the correct app directory and restart:
anvil watchIf you are using --staged-only, remember that only staged files sync.
Changes from Anvil are not appearing locally
Make sure anvil watch is still running. If the watch session looks unhealthy or branch state changed underneath it, stop it and start it again from the correct branch and app folder.
The CLI is using the wrong server
Check your current config:
anvil config listSet the default explicitly if needed:
anvil config set anvilUrl https://anvil.company.comConfig File
anvil-cli stores local settings in config.json.
Common locations:
- macOS:
~/Library/Preferences/anvil-cli/config.json - Linux:
~/.config/anvil-cli/config.json - Windows:
%APPDATA%\\anvil-cli\\Config\\config.json
This includes settings such as:
anvilUrlpreferredEditorverbose
Authentication secrets are stored in the OS keychain when available.
Developing anvil-cli
Build the CLI:
pnpm buildRun in watch mode:
pnpm devType-check:
pnpm tsc --noEmitRun tests:
source tests/setup-test-env.sh
pnpm testRun one test file:
source tests/setup-test-env.sh
pnpm rstest tests/some.test.tsLicense
MIT
