Files
Matt Fiddaman 8c47374b9d ⬆️ mid-month dependency bump (#7506)
* 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
2026-04-15 17:05:26 +00:00
..
2026-04-15 17:05:26 +00:00

@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):

  1. CLI flags (--server-url, --password, etc.)
  2. Environment variables
  3. Config file (via cosmiconfig)
  4. Defaults (dataDir defaults 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": false to 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.name is null for 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