AI-friendly CLI for managing n8n self-hosted instances via the n8n Public API.
Built with Node.js + TypeScript.
AI-first, Human-optional.
| AI Mode (default) | Human Mode (--human) |
|
|---|---|---|
| Output | JSONL for lists, single JSON for items | Colored tables, icons, friendly messages |
| Colors | None (no ANSI escape codes) | Full chalk coloring |
| Errors | {"ok":false,"error":"...","code":401} |
✘ Unauthorized |
| Ideal for | LLM agents, MCP tools, scripts, CI/CD | Terminal users |
Every command outputs deterministic JSON by default:
| Resource | Commands |
|---|---|
| workflow | list, get, create, update, delete, activate, deactivate, transfer, get-tags, set-tags |
| execution | list, get, delete |
| user | list, get, create, delete, set-role |
| tag | list, get, create, update, delete |
| credential | create, delete, transfer, schema |
| variable | list, create, update, delete |
| project | list, create, update, delete, add-user, remove-user, set-user-role |
| audit | generate |
| source-control | pull |
# Global install
npm install -g n8n-open-cli
# Or use npx directly
npx n8n-open-cli workflow listThis installs the CLI binary as n8n-open-cli, so all examples below keep using the n8n-open-cli command name.
git clone <repo-url>
cd n8n-open-cli
npm install
npm run build
npm link # install globallyn8n-open-cli config set \
--base-url https://your-n8n.example.com \
--api-key your-api-key-here
n8n-open-cli config showexport N8N_BASE_URL=https://your-n8n.example.com
export N8N_API_KEY=your-api-key-hereEnvironment variables take precedence over stored config.
# List commands output JSONL — one JSON object per line
n8n-open-cli workflow list
# {"id":"1","name":"My Workflow","active":true,...}
# {"id":"2","name":"Another","active":false,...}
# {"__cursor":"MTIzZTQ1..."}
# Single-item commands output JSON envelope
n8n-open-cli workflow get 123
# {"ok":true,"data":{"id":"123","name":"My Workflow",...}}
n8n-open-cli workflow activate 123
# {"ok":true,"data":{"id":"123","active":true,...}}
n8n-open-cli workflow delete 123
# {"ok":true,"data":null}# Only return specific fields — saves tokens for AI agents
n8n-open-cli workflow list --fields id,name,active
# {"id":"1","name":"My Workflow","active":true}
# {"id":"2","name":"Another","active":false}
n8n-open-cli execution list --fields id,status,workflowId# Add --human at the top level (before subcommand)
n8n-open-cli --human workflow list
n8n-open-cli --human execution list --status error
n8n-open-cli --human tag create --name productionAll write operations (create / update / delete / activate / deactivate / transfer / set-role / set-tags / add-user / remove-user) support --dry-run.
Best Practice: Always run
--dry-runfirst to preview changes, review the diff, and only execute the actual command after manual confirmation. This prevents accidental data loss or unintended modifications.
When --dry-run is used, the CLI will not execute the actual operation. Instead, it fetches the current state, computes the diff, and outputs a preview:
# Step 1: Preview the change
n8n-open-cli workflow activate 123 --dry-run
# {"ok":true,"dryRun":true,"resource":"workflow","id":"123","action":"activate",
# "changes":[{"field":"active","before":false,"after":true}]}
# Step 2: Review the output, then execute
n8n-open-cli workflow activate 123
# Another example: preview before deleting
n8n-open-cli workflow delete 456 --dry-run
# Review what will be deleted, then confirm:
n8n-open-cli workflow delete 456With --human mode, dry-run shows a colored diff view (red for removed/old values, green for added/new values) with a DRY-RUN warning banner.
n8n-open-cli workflow list # list all
n8n-open-cli workflow list --active true # filter active
n8n-open-cli workflow list --tags "prod,critical" # filter by tags
n8n-open-cli workflow list --limit 10 --cursor abc # pagination
n8n-open-cli workflow get <id> # get by ID
n8n-open-cli workflow get <id> --fields id,name,nodes # partial fields
n8n-open-cli workflow create -f workflow.json # create from file
n8n-open-cli workflow update <id> -f workflow.json # update
n8n-open-cli workflow delete <id> # delete
n8n-open-cli workflow activate <id> # activate
n8n-open-cli workflow deactivate <id> # deactivate
n8n-open-cli workflow transfer <id> --destination-project-id <pid>
n8n-open-cli workflow get-tags <id>
n8n-open-cli workflow set-tags <id> --tag-ids "t1,t2"Tip: For any write command above, add
--dry-runto preview changes before executing.
n8n-open-cli execution list
n8n-open-cli execution list --workflow-id <id>
n8n-open-cli execution list --status error
n8n-open-cli execution get <id>
n8n-open-cli execution get <id> --include-data
n8n-open-cli execution delete <id>n8n-open-cli user list
n8n-open-cli user get <id-or-email>
n8n-open-cli user create -f users.json
n8n-open-cli user delete <id>
n8n-open-cli user set-role <id> --role global:adminn8n-open-cli tag list
n8n-open-cli tag get <id>
n8n-open-cli tag create --name "production"
n8n-open-cli tag update <id> --name "staging"
n8n-open-cli tag delete <id>n8n-open-cli credential create -f credential.json
n8n-open-cli credential delete <id>
n8n-open-cli credential transfer <id> --destination-project-id <pid>
n8n-open-cli credential schema slackApin8n-open-cli variable list
n8n-open-cli variable create --key MY_VAR --value "hello"
n8n-open-cli variable update <id> --value "world"
n8n-open-cli variable delete <id>n8n-open-cli project list
n8n-open-cli project create --name "My Project"
n8n-open-cli project update <id> --name "Renamed"
n8n-open-cli project delete <id>
n8n-open-cli project add-user <pid> -f users.json
n8n-open-cli project remove-user <pid> <uid>
n8n-open-cli project set-user-role <pid> <uid> --role editorn8n-open-cli audit generate
n8n-open-cli audit generate --categories credentials,database
n8n-open-cli source-control pull
n8n-open-cli source-control pull --forceimport subprocess, json
result = subprocess.run(
["n8n-open-cli", "workflow", "list", "--fields", "id,name,active"],
capture_output=True, text=True
)
# List commands output JSONL — parse each line
workflows = [json.loads(line) for line in result.stdout.strip().splitlines()]
# Filter out cursor metadata if present
cursor = None
if workflows and "__cursor" in workflows[-1]:
cursor = workflows.pop()["__cursor"]The deterministic output format makes it trivial to wrap as an MCP tool:
// List commands → JSONL (one object per line)
const { stdout } = await exec(`n8n-open-cli workflow list --fields id,name,active`);
const items = stdout.trim().split('\n').map(line => JSON.parse(line));
// Single-item commands → JSON envelope
const { stdout: out } = await exec(`n8n-open-cli workflow get 123`);
const result = JSON.parse(out); // { ok, data?, error?, code? }# Errors are always structured — no need to parse stderr
n8n-open-cli workflow get nonexistent
# {"ok":false,"error":"Not Found","code":404}
n8n-open-cli workflow list
# (with bad API key) {"ok":false,"error":"unauthorized","code":401}npm install
npm run dev -- workflow list # dev mode
npm run build # compile
node dist/index.js workflow list # run built
node dist/index.js --human workflow ls # human modeMIT