* typescript (^5.9.3 -> ^6.0.2) * eslint-plugin-perfectionist (^5.6.0 → ^5.8.0) * @types/node (^22.19.15 → ^22.19.17) * @typescript/native-preview (^7.0.0-dev.20260309.1 → ^7.0.0-dev.20260404.1) * eslint (^9.39.3 → ^9.39.4) * lage (^2.14.19 → ^2.15.5) * lint-staged (^16.3.2 → ^16.4.0) * minimatch (^10.2.4 → ^10.2.5) * vitest (^4.1.0 → ^4.1.2) * better-sqlite3 (^12.6.2 → ^12.8.0) * commander (^13.0.0 → ^13.1.0) * cosmiconfig (^9.0.0 → ^9.0.1) * @chromatic-com/storybook (^5.0.1 → ^5.1.1) * @storybook/addon-a11y (^10.2.16 → ^10.3.4) * @storybook/addon-docs (^10.2.16 → ^10.3.4) * @storybook/react-vite (^10.2.16 → ^10.3.4) * eslint-plugin-storybook (^10.2.16 → ^10.3.4) * storybook (^10.2.16 → ^10.3.4) * @codemirror/language (^6.12.2 → ^6.12.3) * @react-aria/interactions (^3.27.0 → ^3.27.1) * @swc/core (^1.15.18 → ^1.15.24) * @swc/helpers (^0.5.19 → ^0.5.21) * @tanstack/react-query (^5.90.21 → ^5.96.2) * @uiw/react-codemirror (^4.25.7 → ^4.25.9) * @vitejs/plugin-basic-ssl (^2.2.0 → ^2.3.0) * i18next (^25.8.14 → ^25.10.10) * lru-cache (^11.2.6 → ^11.2.7) * react-grid-layout (^2.2.2 → ^2.2.3) * react-i18next (^16.5.6 → ^16.6.6) * rolldown (^1.0.0-rc.12 → ^1.0.0-rc.13) * sass (^1.97.3 → ^1.99.0) * adm-zip (^0.5.16 → ^0.5.17) * csv-parse (^6.1.0 → ^6.2.1) * csv-stringify (^6.6.0 → ^6.7.0) * jest-diff (^30.2.0 → ^30.3.0) * express-rate-limit (^8.3.0 → ^8.3.2) * upgrade yarn to 4.13.0 * react-aria-components (^1.15.1 → ^1.16.0) * @vitejs/plugin-react (^6.0.0 → ^6.0.1) * @codemirror/state (^6.5.4 → ^6.6.0), @codemirror/view (^6.38.7 → ^6.41.0) * react-aria (^3.46.0 → ^3.47.0) * react-error-boundary (^6.0.3 → ^6.1.1) * recharts (^3.7.0 → ^3.8.1) * fast-check (4.5.3 → ^4.6.0) * rollup-plugin-visualizer (^6.0.11 → ^7.0.1) * commander (^13.1.0 → ^14.0.3) * note * coderabbit feedback, and a test for good measure * typescript (^5.9.3 -> ^6.0.2) * @playwright/test (1.58.2 -> 1.59.1) * yarn dedupe
@actual-app/cli
WARNING: This CLI is experimental.
Command-line interface for Actual Budget. Query and modify your budget data from the terminal — accounts, transactions, categories, payees, rules, schedules, and more.
Note: This CLI connects to a running Actual sync server. It does not operate on local budget files directly.
Installation
npm install -g @actual-app/cli
Requires Node.js >= 22.
Quick Start
# Set connection details
export ACTUAL_SERVER_URL=http://localhost:5006
export ACTUAL_PASSWORD=your-password
export ACTUAL_SYNC_ID=your-sync-id # Found in Settings → Advanced → Sync ID
# List your accounts
actual accounts list
# Check a balance
actual accounts balance <account-id>
# View this month's budget
actual budgets month 2026-03
Configuration
Configuration is resolved in this order (highest priority first):
- CLI flags (
--server-url,--password, etc.) - Environment variables
- Config file (via cosmiconfig)
- Defaults (
dataDirdefaults to~/.actual-cli/data)
Environment Variables
| Variable | Description |
|---|---|
ACTUAL_SERVER_URL |
URL of the Actual sync server (required) |
ACTUAL_PASSWORD |
Server password (required unless using token) |
ACTUAL_SESSION_TOKEN |
Session token (alternative to password) |
ACTUAL_SYNC_ID |
Budget Sync ID (required for most commands) |
ACTUAL_DATA_DIR |
Local directory for cached budget data |
Config File
Create an .actualrc.json (or .actualrc, .actualrc.yaml, actual.config.js):
{
"serverUrl": "http://localhost:5006",
"password": "your-password",
"syncId": "1cfdbb80-6274-49bf-b0c2-737235a4c81f"
}
Security: Do not store plaintext passwords in config files (e.g. .actualrc.json, .actualrc, .actualrc.yaml, actual.config.js). Add these files to .gitignore if they contain secrets. Prefer the ACTUAL_SESSION_TOKEN environment variable instead of the password field. See Environment Variables for using a session token.
Global Flags
| Flag | Description |
|---|---|
--server-url <url> |
Server URL |
--password <pw> |
Server password |
--session-token <token> |
Session token |
--sync-id <id> |
Budget Sync ID |
--data-dir <path> |
Data directory |
--format <format> |
Output format: json (default), table, csv |
--verbose |
Show informational messages |
Commands
| Command | Description |
|---|---|
accounts |
Manage accounts |
budgets |
Manage budgets and allocations |
categories |
Manage categories |
category-groups |
Manage category groups |
transactions |
Manage transactions |
payees |
Manage payees |
tags |
Manage tags |
rules |
Manage transaction rules |
schedules |
Manage scheduled transactions |
query |
Run an ActualQL query |
server |
Server utilities and lookups |
Run actual <command> --help for subcommands and options.
Examples
# List all accounts (as a table; excludes closed by default)
actual accounts list [--include-closed] --format table
# Find an entity ID by name
actual server get-id --type accounts --name "Checking"
# Add a transaction (amount in integer cents: -2500 = -$25.00)
actual transactions add --account <id> \
--data '[{"date":"2026-03-14","amount":-2500,"payee_name":"Coffee Shop"}]'
# Export transactions to CSV
actual transactions list --account <id> \
--start 2026-01-01 --end 2026-12-31 --format csv > transactions.csv
# Set budget amount ($500 = 50000 cents)
actual budgets set-amount --month 2026-03 --category <id> --amount 50000
# Run an ActualQL query
actual query run --table transactions \
--select "date,amount,payee" --filter '{"amount":{"$lt":0}}' --limit 10
Amount Convention
All monetary amounts are integer cents when passed as input (flags, JSON):
| CLI Value | Dollar Amount |
|---|---|
5000 |
$50.00 |
-12350 |
-$123.50 |
Output formatting: Table (--format table) and CSV (--format csv) output automatically converts cent values to decimal (e.g. 1665.00 instead of 166500). JSON output always returns raw cents for programmatic use.
Tips & Common Pitfalls
-
Split transactions: When summing or counting transactions, filter
"is_parent": falseto avoid double-counting. A split parent holds the total amount, and its children hold the individual parts — including both would count the total twice. -
Avoid rapid sequential requests: Each CLI invocation opens a new server connection. Running queries in a tight loop (e.g. one per month) may trigger rate limiting or authentication failures. Instead, fetch all data in a single query with a date range filter and process locally:
# Good: single query for the full year actual query run --table transactions \ --filter '{"$and":[{"date":{"$gte":"2025-01-01"}},{"date":{"$lte":"2025-12-31"}}]}' \ --limit 5000 # Bad: one query per month in a loop (may fail with auth errors) for month in 01 02 03 ...; do actual query run ...; done -
Uncategorized transactions:
category.nameisnullfor transactions without a category. Account for this when filtering or grouping by category. -
No date sub-fields in AQL:
date.month,date.year, etc. are not supported as query fields. To group by month, fetch raw transactions with a date range filter and aggregate locally in a script.
Running Locally (Development)
If you're working on the CLI within the monorepo:
# 1. Build the CLI
yarn build:cli
# 2. Start a local sync server (in a separate terminal)
yarn start:server-dev
# 3. Open http://localhost:5006 in your browser, create a budget,
# then find the Sync ID in Settings → Advanced → Sync ID
# 4. Run the CLI directly from the build output
ACTUAL_SERVER_URL=http://localhost:5006 \
ACTUAL_PASSWORD=your-password \
ACTUAL_SYNC_ID=your-sync-id \
node packages/cli/dist/cli.js accounts list
# Or use a shorthand alias for convenience
alias actual-dev="node $(pwd)/packages/cli/dist/cli.js"
actual-dev budgets list