A Go-based command-line interface for managing Kestra flows, executions, triggers, namespaces, key-value store, namespace files, apps, dashboards, assets, blueprints, test suites, IAM users, groups, roles, service accounts, bindings, and invitations.
Every version in the badges above is exercised by the e2e matrix on each run. The source of truth is COMPATIBLE_KESTRA_VERSION.properties — edit that file, then run .github/scripts/render-compat-badges.sh to regenerate the badges (CI checks they are in sync).
Install the latest kestractl v3 release. kestractl v3 targets Kestra 2.x and works against Kestra 1.3 for everyday commands (flows, executions, namespace files, KV, namespaces); features that only exist in Kestra 2.0 are refused with a clear error on a 1.x server. (kestractl's own version is independent of Kestra's — v3 is a breaking change to the CLI itself, not a new Kestra target.)
curl -fsSL https://raw.githubusercontent.com/kestra-io/kestractl/main/install-scripts/install.sh | bashInstall the latest v1 release instead (full Kestra 1.x feature set, e.g. namespace plugin defaults and superadmin management):
curl -fsSL https://raw.githubusercontent.com/kestra-io/kestractl/main/install-scripts/install.sh | VERSION=1 bashInstall a specific version or custom directory:
curl -fsSL https://raw.githubusercontent.com/kestra-io/kestractl/main/install-scripts/install.sh | VERSION=1.18.1 INSTALL_DIR=~/.local/bin bashThe script resolves the release through the GitHub REST API, which is rate-limited per IP for anonymous callers — shared CI egress IPs can hit that limit and fail with HTTP 403. Set GITHUB_TOKEN (or GH_TOKEN) and the API calls are authenticated instead; it is optional and no token is needed for a normal install:
curl -fsSL https://raw.githubusercontent.com/kestra-io/kestractl/main/install-scripts/install.sh | GITHUB_TOKEN="$GITHUB_TOKEN" bashdownload the compressed or plain binary for your platform at https://github.com/kestra-io/kestractl/releases
example:
curl -fsSL -o kestractl https://github.com/kestra-io/kestractl/releases/download/1.0.0/kestractl_1.0.0_linux_arm64
chmod +x kestractl
Every release publishes a multi-arch (linux/amd64 + linux/arm64) image to both
Docker Hub and GitHub Container Registry:
docker run --rm kestra/kestractl:latest --help
docker run --rm ghcr.io/kestra-io/kestractl:latest --help| Tag | Contents |
|---|---|
latest, X, X.Y, X.Y.Z |
Alpine based, with bash, git and curl — use this in CI jobs that run scripts |
latest-static, X-static, X.Y-static, X.Y.Z-static |
distroless, no shell — smallest surface, runs kestractl only |
latest, X and X.Y follow the newest stable release. Pin X.Y.Z in CI if you want a
release to stay put; a prerelease, should one be published, only ever moves X.
Configure it either with KESTRACTL_* environment variables:
docker run --rm \
-e KESTRACTL_HOST=https://kestra.example.com \
-e KESTRACTL_TENANT=main \
-e KESTRACTL_USERNAME=admin@example.com \
-e KESTRACTL_PASSWORD='...' \
kestra/kestractl:latest flows listor by mounting a config file. The images run as a non-root user, so mount it at that
user's home: /home/kestractl/.kestractl (Alpine) or /home/nonroot/.kestractl
(-static).
docker run --rm \
-v ~/.kestractl:/home/kestractl/.kestractl:ro \
-v "$PWD/flows:/flows:ro" \
kestra/kestractl:latest flows deploy /flowsDeploying flows from GitLab CI:
deploy-flows:
image: kestra/kestractl:latest
variables:
KESTRACTL_HOST: https://kestra.example.com
KESTRACTL_TENANT: main
script:
- kestractl flows validate ./flows
- kestractl flows deploy ./flowsKESTRACTL_TOKEN, KESTRACTL_USERNAME and KESTRACTL_PASSWORD belong in your CI's
masked/protected variables — never in the job definition.
Note: GitLab CI and GitHub Actions container jobs override the image entrypoint and run
your script through a shell, so use the default (Alpine) tag there. The -static tag
has no shell and only works with docker run/kubectl run style invocations.
git clone git@github.com:kestra-io/kestractl.git
# Download dependencies (requires Go 1.25+)
go mod download
# Build the binary
go build -o kestractlYou can also install it into your $GOBIN:
go install ./...Configure your Kestra instance and credentials:
# Token auth
kestractl config add default http://localhost:8080 main --token YOUR_TOKEN --default
# Basic auth (username + password)
kestractl config add default http://localhost:8080 main --username you@example.com --password YOUR_PASSWORD --defaultThis creates a configuration file at ~/.kestractl/config.yaml:
contexts:
default:
host: http://localhost:8080
tenant: main
auth_method: token
token: YOUR_TOKEN
headers: # Optional: persisted extra HTTP headers
- "X-Custom-Header:value"
default_context: defaultYou can manage multiple Kestra environments (development, staging, production):
# Add multiple contexts
kestractl config add dev http://localhost:8080 main --token DEV_TOKEN
kestractl config add prod https://prod.kestra.io production --token PROD_TOKEN
# List all contexts
kestractl config show
# Switch between contexts
kestractl config use prodYou can also configure kestractl using environment variables, which override config file settings:
export KESTRACTL_HOST=http://localhost:8080
export KESTRACTL_TENANT=main
export KESTRACTL_TOKEN=YOUR_TOKEN
export KESTRACTL_OUTPUT=json # Optional: table or json
export KESTRACTL_HEADER="X-Custom-Header:value" # Optional: extra HTTP headerFollowing the 12-factor app methodology, configuration is resolved in this order (highest to lowest):
- Command-line flags (
--host,--token, etc.) - Highest priority - Environment variables (
KESTRACTL_HOST,KESTRACTL_TOKEN, etc.) - Config file (
~/.kestractl/config.yamlor custom via--config) - Default values - Lowest priority
This allows you to:
- Store credentials securely in
~/.kestractl/config.yamlfor daily use - Override with environment variables in CI/CD pipelines
- Override with flags for one-off commands
kestractl sends anonymous telemetry to help the Kestra team understand real usage and improve the product over time, and it never blocks command execution.
Set KESTRACTL_TELEMETRY_DISABLED=true to disable telemetry.
kestractl warns on stderr when a newer release is available. The lookup runs at most once every 24 hours — the result is cached in ~/.kestractl/check_for_new_available_version.json, so all but the first command you run after a full day are served from that cache with no network call at all.
The lookup itself is asynchronous: it runs in the background alongside your command rather than before it, so it does not add to the time your command takes. If it has not come back by the time the command finishes, kestractl gives up and the notice simply appears on your next run. Failures are silent, and the check is skipped automatically on CI and for dev builds.
Set KESTRACTL_VERSION_CHECK_DISABLED=true to turn it off entirely.
All commands support global flags for connection and output configuration:
--host- Kestra host URL--token/-t- API authentication token--username- Basic auth username (alternative to--token)--password- Basic auth password (alternative to--token)--tenant- Tenant name--header- Extra HTTP header to include in all requests (format:Key:Value, repeatable)--output/-o- Output format (tableorjson)--config- Custom config file path (default:~/.kestractl/config.yaml)--verbose/-v- Verbose output (warning: prints credentials in HTTP requests)
# Add a new context
kestractl config add dev http://localhost:8080 main --token YOUR_TOKEN
# Add and set as default
kestractl config add prod https://prod.kestra.io production --token PROD_TOKEN --default
# Add with extra HTTP headers (persisted in the context)
kestractl config add dev http://localhost:8080 main --token YOUR_TOKEN \
--header "X-Custom-Header:value" --header "Authorization:Bearer extra"
# List all contexts
kestractl config show
# Switch default context
kestractl config use prod
# Remove a context
kestractl config remove dev# List flows in a namespace (alias: ls)
kestractl flows list my.namespace
# List flows across all namespaces
kestractl flows list
# List flows in a namespace with pagination
kestractl flows list-by-namespace my.namespace --page 1 --size 50
# List deprecated flows
kestractl flows list-deprecated
# Get a flow source (aliases: show, describe)
kestractl flows get my.namespace my-flow
# Get a specific task within a flow
kestractl flows task my.namespace my-flow my-task-id
# Deploy a single flow from YAML (aliases: create, apply)
kestractl flows deploy path/to/flow.yaml
# Deploy all flows in a directory (recursive)
kestractl flows deploy ./flows/
# Deploy with namespace override (all flows go to specified namespace)
kestractl flows deploy ./flows/ --namespace prod.namespace
# Deploy under a namespace prefix (keeps each flow's own namespace beneath it).
# Only each flow's own namespace is prefixed: Subflow targets, Flow trigger
# conditions, namespace files and KV lookups still point at the unprefixed ones.
kestractl flows deploy ./flows/ --namespace-prefix staging.pr42
# Deploy with every trigger disabled
kestractl flows deploy ./flows/ --disable-triggers
# Override existing flows
kestractl flows deploy ./flows/ --override
# Stop on first error (fail-fast)
kestractl flows deploy ./flows/ --fail-fast
# Validate a single flow or directory
kestractl flows validate path/to/flow.yaml
kestractl flows validate ./flows/
# Validate the flows already stored on the instance (no local copy needed)
kestractl flows validate-by-query --namespace my.namespace
kestractl flows validate-by-query --all
# Validate a task or trigger definition inline
kestractl flows validate-task --namespace my.namespace --flow my-flow --task-id my-task
kestractl flows validate-trigger --namespace my.namespace --flow my-flow --trigger-id my-trigger
# Search flows by source content
kestractl flows search-by-source --query "http.request"
# Bulk-update flows from YAML
kestractl flows bulk-update --file flows.yaml
# Generate the graph topology from a flow source file
kestractl flows generate-graph-from-source --file flow.yaml
# Show the graph topology of an existing flow (optionally a specific revision)
kestractl flows graph my.namespace my-flow --revision 3 --output json
# List available expressions for a flow
kestractl flows expressions --namespace my.namespace --flow my-flow
# Show namespace-level dependencies
kestractl flows namespace-dependencies my.namespace
# Show dependencies of a specific flow
kestractl flows dependencies my.namespace my-flow
# Enable / disable flows
kestractl flows enable my.namespace my-flow
kestractl flows disable my.namespace my-flow
# Delete a flow
kestractl flows delete my.namespace my-flow
# Delete / disable / enable matching a query
kestractl flows delete-by-query --namespace my.namespace --query old-
kestractl flows disable-by-query --namespace my.namespace
kestractl flows enable-by-query --namespace my.namespace
# Export flows
kestractl flows export --namespace my.namespace --output-file flows.zip
kestractl flows export-by-ids my.namespace/flow-a my.namespace/flow-b --output-file export.zip
kestractl flows export-by-query --namespace my.namespace --output-file export.zip
# Import flows from a ZIP archive
kestractl flows import flows.zip
# Sync an entire namespace from a YAML file (delete flows absent from the file)
kestractl flows namespace-sync my.namespace flows.yaml --delete --override
# View and manage flow revisions
kestractl flows revisions my.namespace my-flow
kestractl flows delete-revisions my.namespace my-flow --before-revision 5
# Manage concurrency limits
kestractl flows concurrency-limits my.namespace my-flow
kestractl flows update-concurrency my.namespace my-flow --limit 10After upgrading an instance and migrating flow definitions, two commands answer "did that work?" without exporting anything to disk:
# What does this instance use, and what needs attention for a 1.x -> 2.0 upgrade?
kestractl flows usage-report
# Are the flows now stored on the instance actually valid?
kestractl flows validate-by-query --allA selection is required: --namespace, --flow or --filter to scope the run,
or --all for every flow of the tenant. Validating a whole instance is
deliberately something you ask for by name.
validate-by-query exits non-zero when any flow has constraint violations,
which makes it usable as a CI gate:
kestractl flows validate-by-query --all --output jsonDrafts are not covered: the export the sources are read from deliberately skips them, so a draft-headed flow is validated at its last saved revision and a draft-only flow is not validated at all.
# Trigger a flow execution (aliases: trigger, execute)
kestractl executions run my.namespace my-flow
# Trigger a flow with inputs (repeatable)
kestractl executions run my.namespace my-flow --input branch=main --input dry_run=true
# Trigger and wait for completion
kestractl executions run my.namespace my-flow --wait
# Get execution details (aliases: show, describe)
kestractl executions get 2TLGqHrXC9k8BczKJe5djX
# List executions
kestractl executions list --namespace my.namespace --flow my-flow
# Watch an execution in real time (alias: follow) — exits non-zero on failure
kestractl executions watch 2TLGqHrXC9k8BczKJe5djX
# Get the latest execution for each flow
kestractl executions latest --flow my.namespace:my-flow --flow my.namespace:other-flow
# Control execution state
kestractl executions kill 2TLGqHrXC9k8BczKJe5djX
kestractl executions pause 2TLGqHrXC9k8BczKJe5djX
kestractl executions resume 2TLGqHrXC9k8BczKJe5djX
kestractl executions restart 2TLGqHrXC9k8BczKJe5djX
kestractl executions force-run 2TLGqHrXC9k8BczKJe5djX
# Replay and unqueue
kestractl executions replay 2TLGqHrXC9k8BczKJe5djX
kestractl executions replay-with-inputs 2TLGqHrXC9k8BczKJe5djX --input key=value
kestractl executions unqueue 2TLGqHrXC9k8BczKJe5djX
# Labels
kestractl executions set-labels 2TLGqHrXC9k8BczKJe5djX env=prod team=platform
# Bulk operations by IDs
kestractl executions set-labels-bulk env=prod --ids id1 --ids id2
kestractl executions unqueue-bulk id1 id2 id3
kestractl executions change-status-by-ids --status SUCCESS id1 id2
# Bulk operations by query
kestractl executions kill-by-query --namespace my.namespace --flow my-flow
kestractl executions pause-by-query --namespace my.namespace
kestractl executions resume-by-query --namespace my.namespace
kestractl executions restart-by-query --namespace my.namespace
kestractl executions replay-by-query --namespace my.namespace --latest-revision
kestractl executions force-run-by-query --namespace my.namespace
kestractl executions delete-by-query --namespace my.namespace --delete-logs --delete-storage
kestractl executions unqueue-by-query --namespace my.namespace
kestractl executions set-labels-by-query env=prod --namespace my.namespace
kestractl executions update-status-by-query --namespace my.namespace --new-status KILLED
# Filter by any field with --filter FIELD:OPERATION:VALUE (e.g. STATE:EQUALS:SUCCESS)
kestractl executions kill-by-query --filter STATE:EQUALS:RUNNING
# Trigger an execution via webhook (--method GET|POST|PUT, --path appends a URL suffix)
kestractl executions trigger-webhook my.namespace my-flow my-webhook-key
kestractl executions trigger-webhook my.namespace my-flow my-webhook-key --method POST
kestractl executions trigger-webhook my.namespace my-flow my-webhook-key --method PUT --path extra/segment
# Flow graph and info
kestractl executions flow-graph 2TLGqHrXC9k8BczKJe5djX
kestractl executions flow-info my.namespace my-flow
kestractl executions flow-info-by-id 2TLGqHrXC9k8BczKJe5djX
# Download execution output files
kestractl executions download-file 2TLGqHrXC9k8BczKJe5djX --path outputs/result.csv
kestractl executions file-metadata 2TLGqHrXC9k8BczKJe5djX --path outputs/result.csv
# Evaluate an expression against an execution
kestractl executions eval-expression 2TLGqHrXC9k8BczKJe5djX "{{ outputs.myTask.value }}"
# Force-change the status of an execution
kestractl executions change-status 2TLGqHrXC9k8BczKJe5djX SUCCESS
# Update a specific task run's state
kestractl executions update-taskrun 2TLGqHrXC9k8BczKJe5djX taskRunId SUCCESS
# Delete an execution
kestractl executions delete 2TLGqHrXC9k8BczKJe5djX# List all triggers
kestractl triggers list
# List triggers for a specific flow
kestractl triggers search-for-flow my.namespace my-flow
# Enable / disable a trigger
kestractl triggers enable my.namespace my-flow my-trigger
kestractl triggers disable my.namespace my-flow my-trigger
# Unlock a locked trigger
kestractl triggers unlock my.namespace my-flow my-trigger
# Restart a trigger
kestractl triggers restart my.namespace my-flow my-trigger
# Update a trigger (e.g. mark disabled)
kestractl triggers update my.namespace my-flow my-trigger --disabled
# Delete a trigger
kestractl triggers delete my.namespace my-flow my-trigger
# Bulk operations by IDs (format: namespace/flowId/triggerId)
kestractl triggers delete-by-ids my.ns/my-flow/sched my.ns/my-flow/webhook
kestractl triggers unlock-by-ids my.ns/my-flow/sched
kestractl triggers disable-by-ids my.ns/my-flow/sched
kestractl triggers enable-by-ids my.ns/my-flow/sched
# Bulk operations by query
kestractl triggers delete-by-query --namespace my.namespace
kestractl triggers unlock-by-query --namespace my.namespace
kestractl triggers disable-by-query --namespace my.namespace
kestractl triggers enable-by-query --namespace my.namespace
# Backfill management (single trigger)
kestractl triggers create-backfill my.namespace my-flow my-trigger \
--start 2024-01-01T00:00:00Z --end 2024-02-01T00:00:00Z
kestractl triggers backfill-pause my.namespace my-flow my-trigger
kestractl triggers backfill-unpause my.namespace my-flow my-trigger
kestractl triggers backfill-delete my.namespace my-flow my-trigger
# Backfill management by IDs
kestractl triggers pause-backfill-by-ids my.ns/my-flow/sched
kestractl triggers unpause-backfill-by-ids my.ns/my-flow/sched
kestractl triggers delete-backfill-by-ids my.ns/my-flow/sched
# Backfill management by query
kestractl triggers pause-backfill-by-query --namespace my.namespace
kestractl triggers unpause-backfill-by-query --namespace my.namespace
kestractl triggers delete-backfill-by-query --namespace my.namespace
# Export all triggers as CSV
kestractl triggers export-csv
kestractl triggers export-csv --output-file triggers.csv# List all namespaces (alias: ls)
kestractl namespaces list
# Filter namespaces with query
kestractl namespaces list --query my.namespace
# Autocomplete namespace names
kestractl namespaces autocomplete --query my.
# Get namespace details
kestractl namespaces get my.namespace
# Create / update / delete a namespace
kestractl namespaces create my.namespace
kestractl namespaces update my.namespace --description "Production namespace"
kestractl namespaces delete my.namespace
# Set namespace variables (repeatable --variable, or a YAML/JSON file); replaces
# the full variable set on that namespace
kestractl namespaces create my.namespace --variable env=prod --variable region=eu
kestractl namespaces update my.namespace --variables-file variables.yml
# View inherited secrets and variables
kestractl namespaces inherited-secrets my.namespace
kestractl namespaces inherited-variables my.namespaceSupported types: STRING, NUMBER, BOOLEAN, DATETIME, DATE, DURATION, JSON
# List all key-value entries
kestractl kv list
# List key-value entries in a namespace
kestractl kv list my.namespace
# Set a key — format: kv set <namespace> <type> <key> <value>
kestractl kv set my.namespace STRING api_key "my-secret"
kestractl kv set my.namespace NUMBER retries 3
kestractl kv set my.namespace BOOLEAN enabled true
kestractl kv set my.namespace JSON settings '{"feature":true}'
# Set a key with a TTL (ISO 8601 duration)
kestractl kv set my.namespace STRING session_token "abc" --ttl PT1H
kestractl kv set my.namespace STRING cache_key "value" --ttl P7D
# Update an existing key (fails if key does not exist)
kestractl kv update my.namespace NUMBER retries 5
kestractl kv update my.namespace STRING session_token "new" --ttl PT30M
# Read a key (shows type and value)
kestractl kv get my.namespace api_key
# Delete a key (alias: rm)
kestractl kv delete my.namespace api_key# List files at the namespace root (alias: ls)
kestractl nsfiles list my.namespace
# List files in a directory
kestractl nsfiles list my.namespace --path workflows/
# List files recursively
kestractl nsfiles list my.namespace --path workflows/ --recursive
# Get a file's raw content (alias: cat)
kestractl nsfiles get my.namespace workflows/example.yaml
# Get a specific revision
kestractl nsfiles get my.namespace workflows/example.yaml --revision 3
# Upload a single file
kestractl nsfiles upload my.namespace ./local.txt workflows/local.txt
# Upload a directory (recursive)
kestractl nsfiles upload my.namespace ./assets resources
# Override existing files
kestractl nsfiles upload my.namespace ./assets resources --override
# Stop on the first error
kestractl nsfiles upload my.namespace ./assets resources --fail-fast
# Skip the pre-flight namespace existence check
kestractl nsfiles upload my.namespace ./assets resources --allow-missing-namespace
# Delete a file
kestractl nsfiles delete my.namespace workflows/example.yaml
# Delete a directory recursively
kestractl nsfiles delete my.namespace workflows --recursive
# Ignore missing targets
kestractl nsfiles delete my.namespace workflows/example.yaml --force# Download every plugin JAR for a given Kestra version into ./plugins
kestractl plugins download 1.3.9
# Custom output directory
kestractl plugins download 1.3.9 --plugins-dir ./vendor/plugins
# Parallel downloads
kestractl plugins download 1.3.9 --concurrency 4
# `develop` and `latest` are aliases for the in-development version
kestractl plugins download develop
# Bootstrap a standalone/remote worker: download only the "core" plugins required
# by a Kestra configuration — internal storage, secret manager, and the
# queue/repository backend. Bundled backends (local storage, JDBC, Kafka) are
# skipped; enterprise backends need --edition ALL (the default) or EE.
kestractl plugins download 1.3.9 --from-config /etc/kestra/application.yaml
# Preview the core plugins a config needs without downloading (pipes into download)
kestractl plugins list 1.3.9 --from-config /etc/kestra/application.yaml
# Download named plugins at the versions compatible with a Kestra version.
# --compatible-for resolves each groupId:artifactId from the same catalog
# `plugins list` prints, so no shell parsing is needed to pin one plugin.
kestractl plugins download --compatible-for 2.0.2 \
--plugins io.kestra.storage:storage-s3 \
--plugins-dir ./plugins
# The version argument does the same thing when --plugins is unversioned
kestractl plugins download 2.0.2 --plugins io.kestra.storage:storage-s3
# Download a single plugin by exact coordinates, or resolved from a Kestra version
kestractl plugins get io.kestra.plugin:plugin-kafka:1.6.0
kestractl plugins get io.kestra.storage:storage-s3 --compatible-for 2.0.2An artifact that is not in the compatibility set for that Kestra version fails
with a non-zero exit naming it. A coordinate that pins its own version keeps it;
when --compatible-for was passed explicitly, the override is reported.
# Generate a worker registration token (runs offline, no Kestra instance required)
kestractl workers registration-tokens generate# List dashboards (alias: ls)
kestractl dashboards list
kestractl dashboards list --query my-dashboard --output json
# Get dashboard details (aliases: show, describe)
kestractl dashboards get <id>
# Create a dashboard from a YAML file
kestractl dashboards create --file my-dashboard.yaml
# Update an existing dashboard
kestractl dashboards update <id> --file my-dashboard.yaml
# Delete a dashboard (alias: rm)
kestractl dashboards delete <id>
# Show the tenant's default dashboard settings
kestractl dashboards defaults
# Validate a dashboard or a single chart definition
kestractl dashboards validate --file my-dashboard.yaml
kestractl dashboards validate-chart --file my-chart.yaml
# Preview a chart's data without saving it
kestractl dashboards preview-chart --file my-chart.yaml --output json
# Fetch the data for a chart of an existing dashboard
kestractl dashboards chart-data <dashboard-id> <chart-id>
kestractl dashboards chart-data <dashboard-id> <chart-id> --file filters.yaml --output json
# Export chart data as CSV (to stdout or --output-file)
kestractl dashboards export-chart-csv --file my-chart.yaml --output-file chart.csv
kestractl dashboards export-chart-data-csv <dashboard-id> <chart-id> --output-file chart.csvApps are low-code interfaces built on top of flows.
# List apps (alias: ls)
kestractl apps list
kestractl apps list --namespace my.namespace --output json
# Get app details (aliases: show, describe)
kestractl apps get <uid>
# Deploy a new app from a YAML file
kestractl apps deploy --file my-app.yaml
# Update an existing app
kestractl apps update <uid> --file my-app.yaml
# Enable / disable an app
kestractl apps enable <uid>
kestractl apps disable <uid>
# Delete an app (alias: rm)
kestractl apps delete <uid>
# Export all apps as a ZIP archive
kestractl apps export --output-file apps.zip
# Import apps from a ZIP archive
kestractl apps import apps.zip
# Bulk enable / disable / delete multiple apps
kestractl apps bulk-enable uid-1 uid-2 uid-3
kestractl apps bulk-disable uid-1 uid-2 uid-3
kestractl apps bulk-delete uid-1 uid-2 --yes
# List all tags used across apps
kestractl apps tags
# Search apps from the catalog
kestractl apps catalog
kestractl apps catalog --query reporting --output json
# Inspect files produced by an app execution view
kestractl apps file-meta <view-id> --path /path/to/file
kestractl apps file-preview <view-id> --path /path/to/file --max-rows 50
# Download logs for an app execution
kestractl apps logs <view-id> --min-level ERROR --output-file app.logA reusable inputs block is a named set of flow input definitions that flows reference through a REUSABLE_INPUTS input. Requires a Kestra EE 2.0.1 or later server — earlier ones have no reusable-inputs routes and answer 404.
list and get resolve namespace inheritance — a block defined in a parent namespace is visible from its children. revisions, create, update and delete do not: they act on the exact namespace given. So update on a namespace that only inherits a block creates a shadowing copy there instead of saving a new revision of the parent's — update the namespace get --output json reports.
# List the blocks visible from a namespace (alias: ls)
kestractl reusable-inputs list my.namespace
kestractl reusable-inputs list my.namespace --page 2 --size 20 --output json
# Print a block's YAML source (aliases: show, describe)
kestractl reusable-inputs get my.namespace my-block
# Pin an older revision, with the server-managed fields
kestractl reusable-inputs get my.namespace my-block --revision 1 --output json
# List a block's revisions
kestractl reusable-inputs revisions my.namespace my-block
# Create a block (fails if it already exists)
kestractl reusable-inputs create my.namespace my-block --file my-block.yaml
# Save a new revision
kestractl reusable-inputs update my.namespace my-block --file my-block.yaml
# Delete a block (alias: rm)
kestractl reusable-inputs delete my.namespace my-block --yes
# List the namespaces that define at least one block
kestractl reusable-inputs namespaces# List assets (alias: ls)
kestractl assets list
kestractl assets list --output json
# Get asset details (aliases: show, describe)
kestractl assets get <id>
# Create an asset from a file
kestractl assets create --name my-asset --file asset.csv
# Delete an asset (alias: rm)
kestractl assets delete <id>
# Show an asset's dependency graph (alias: deps)
kestractl assets dependencies <id> --expand-all --output json
# Bulk-delete assets by IDs or by query filters
kestractl assets delete-by-ids id1 id2 id3
kestractl assets delete-by-query --namespace my.namespace
kestractl assets delete-by-query --filter NAMESPACE:EQUALS:my.namespace --purge
# Inspect and manage lineage events (alias: lineage)
kestractl assets lineage-events list --output json
kestractl assets lineage-events delete-by-query --namespace my.namespace
# Inspect and manage asset usages (alias: usage)
kestractl assets usages list --output json
kestractl assets usages delete-by-query --namespace my.namespace# Search community blueprints
kestractl blueprints community search --query "kafka"
kestractl blueprints community search --query "etl" --output json
# Get a community blueprint
kestractl blueprints community get <id>
# Get the flow source of a community blueprint
kestractl blueprints community source <id>
# Get the topology graph of a community blueprint
kestractl blueprints community graph <id> --output json
# Manage internal flow blueprints (Enterprise Edition)
kestractl blueprints flow list
kestractl blueprints flow get <id>
kestractl blueprints flow get <id> --legacy # use the legacy /blueprints/flow/{id} endpoint
kestractl blueprints flow create --title "My Blueprint" --source-file blueprint.yaml --tag etl
kestractl blueprints flow update <id> --title "My Blueprint" --source-file blueprint.yaml
kestractl blueprints flow delete <id>
# Generate a flow source from a flow blueprint template
kestractl blueprints flow use-template <id> --input env=prod --input region=eu
# Manage internal/custom blueprints (Enterprise Edition)
kestractl blueprints custom get <id>
kestractl blueprints custom source <id>
kestractl blueprints custom create --title "My Blueprint" --source-file blueprint.yaml
kestractl blueprints custom update <id> --title "My Blueprint" --source-file blueprint.yaml
kestractl blueprints custom delete <id># List test suites (alias: ls)
kestractl test-suites list
kestractl test-suites list --namespace my.namespace
# Get a test suite
kestractl test-suites get my.namespace my-test-suite
# Create / update a test suite from a YAML file
kestractl test-suites create --file suite.yaml
kestractl test-suites update my.namespace my-test-suite --file suite.yaml
# Validate a test suite YAML definition without creating it
kestractl test-suites validate --file suite.yaml
# Run a test suite
kestractl test-suites run my.namespace my-test-suite
# Run test suites matching a query
kestractl test-suites run-by-query --namespace my.namespace
# Bulk enable / disable / delete
kestractl test-suites delete-bulk my.namespace/suite-a my.namespace/suite-b
kestractl test-suites disable-bulk my.namespace/suite-a
kestractl test-suites enable-bulk my.namespace/suite-a
# Query and retrieve results
kestractl test-suites search-results --namespace my.namespace
kestractl test-suites last-result --ids my.namespace/suite-a --ids my.namespace/suite-b
kestractl test-suites get-result <result_id>
# Delete a test suite
kestractl test-suites delete my.namespace my-test-suiteUser management requires Kestra Enterprise Edition. Users are instance-level resources.
Use
--user-passwordto set a user's password — not--password, which is the global basic-auth flag used to authenticate the CLI itself.
# List / filter users (alias: ls)
kestractl users list
kestractl users list --query alice --output json
# Get user details (alias: show, describe)
kestractl users get <user_id>
# Autocomplete user names
kestractl users autocomplete --query ali
# Create a user (--email is required)
kestractl users create --email alice@example.com --first-name Alice --user-password 'S3cret!'
# Create a super-admin
kestractl users create --email bob@example.com --superadmin
# Update a user — only the flags you pass change; other attributes are preserved
kestractl users update <user_id> --first-name Alicia
kestractl users update <user_id> --superadmin=false
# Set a user's password
kestractl users set-password <user_id> --user-password 'N3wPass!'
# Change your own password
kestractl users change-my-password --old-password 'OldPass!' --new-password 'N3wPass!'
# Grant / revoke super-admin status
kestractl users set-super-admin <user_id> --superadmin
kestractl users set-super-admin <user_id> --superadmin=false
# Mark a user as restricted, or lift the restriction (targeted PATCH)
kestractl users set-restricted <user_id> --restricted=true
kestractl users set-restricted <user_id> --restricted=false
# Delete an auth method for a user
kestractl users delete-auth-method <user_id> BASIC_AUTH
# Set the groups a user belongs to in the active tenant (no --group clears them)
kestractl users set-groups <user_id> --group <group_id>
# Impersonate a user (returns an impersonation token)
kestractl users impersonate <user_id>
# Revoke all refresh tokens for a user
kestractl users revoke-refresh-token <user_id>
# Delete a user (alias: rm) — prompts for confirmation unless --yes
kestractl users delete <user_id>
kestractl users delete <user_id> --yes
# Manage a user's API tokens (the full token is shown only once, at creation)
kestractl users tokens create <user_id> --name ci-token
kestractl users tokens list <user_id>
kestractl users tokens delete <user_id> <token_id>Group management requires Kestra Enterprise Edition. Groups are tenant-scoped resources.
# List / filter groups (alias: ls)
kestractl groups list
kestractl groups list --query admins --output json
# Get group details (alias: show, describe)
kestractl groups get <group_id>
# Autocomplete group names
kestractl groups autocomplete --query adm
# Look up multiple groups by IDs
kestractl groups list-by-ids <id1> <id2>
# Create a group (--name is required; --member is repeatable for initial members)
kestractl groups create --name admins --description 'Platform admins'
kestractl groups create --name admins --member <user_id> --member <user_id>
# Update a group — only the flags you pass change; other attributes are preserved
kestractl groups update <group_id> --description 'Updated description'
kestractl groups update <group_id> --name platform-admins
# Set a user's group membership (replaces all current memberships in this group)
kestractl groups set-membership <group_id> <user_id>
# Delete a group (alias: rm) — prompts for confirmation unless --yes
kestractl groups delete <group_id>
kestractl groups delete <group_id> --yes
# Manage group members
kestractl groups members list <group_id>
kestractl groups members add <group_id> <user_id>
kestractl groups members remove <group_id> <user_id>Role management requires Kestra Enterprise Edition. Roles are tenant-scoped (the active tenant is used).
A role carries a permissions payload: a map of resource type (e.g. FLOW,
EXECUTION, NAMESPACE, SECRET, KVSTORE, …) to a list of permission levels
(READ, CREATE, UPDATE, DELETE). You can provide it inline with the
repeatable --permission TYPE:LEVEL[,LEVEL] flag, or from a YAML/JSON file with
--permissions-file — but not both at once.
# List / filter roles (alias: ls)
kestractl roles list
kestractl roles list --query editor --output json
kestractl roles list --page 1 --size 50 --sort name:asc
# Get role details, including its permissions (aliases: show, describe)
kestractl roles get <role_id>
# Autocomplete role names
kestractl roles autocomplete --query edi
# Look up multiple roles by IDs
kestractl roles list-from-ids <id1> <id2>
# Create a role with inline permissions (--name is required, plus at least one permission)
kestractl roles create --name editor \
--description "Can edit flows and view executions" \
--permission FLOW:READ,CREATE,UPDATE \
--permission EXECUTION:READ
# Create a role from a permissions file (YAML or JSON)
kestractl roles create --name viewer --permissions-file perms.yaml
# perms.yaml
# FLOW:
# - READ
# EXECUTION:
# - READ
# Update a role — only the flags you pass change; other attributes are preserved.
# Passing --permission replaces the entire permissions block (it does not merge).
kestractl roles update <role_id> --description "Updated description"
kestractl roles update <role_id> --permission FLOW:READ,CREATE,UPDATE,DELETE
kestractl roles update <role_id> --default
# Delete a role (alias: rm) — prompts for confirmation unless --yes
kestractl roles delete <role_id>
kestractl roles delete <role_id> --yesService account management requires Kestra Enterprise Edition. Service accounts
are instance-level resources (command aliases: service-account, sa).
updateis a partial update of the name/description only. Tenant access, super-admin status and group membership are left untouched — set those at creation time.
# List service accounts (alias: ls)
kestractl service-accounts list
kestractl service-accounts list --output json
kestractl service-accounts list --page 1 --size 50 --sort name:asc
# Get service account details (aliases: show, describe)
kestractl service-accounts get <service_account_id>
# Create a service account (--name is required; lowercase alphanumeric and dashes)
kestractl service-accounts create --name ci-bot --description "CI pipeline"
# Create a super-admin service account with tenant access (--tenant-grant is repeatable)
kestractl service-accounts create --name ops-bot --superadmin --tenant-grant main
# Update name/description — other attributes are preserved
kestractl service-accounts update <service_account_id> --description "Updated description"
kestractl service-accounts update <service_account_id> --name new-bot-name
# Grant / revoke super-admin status
kestractl service-accounts set-super-admin <service_account_id> --superadmin
kestractl service-accounts set-super-admin <service_account_id> --superadmin=false
# Delete a service account (alias: rm) — prompts for confirmation unless --yes
kestractl service-accounts delete <service_account_id>
kestractl service-accounts delete <service_account_id> --yes
# Manage a service account's API tokens (the full token is shown only once, at creation)
kestractl service-accounts tokens create <service_account_id> --name deploy-token
kestractl service-accounts tokens create <service_account_id> --name short-lived --max-age P30D --extended
kestractl service-accounts tokens list <service_account_id>
kestractl service-accounts tokens delete <service_account_id> <token_id>IAM role bindings assign a role to a user, group, or service account within a tenant.
# List bindings (alias: ls)
kestractl bindings list
kestractl bindings list --output json
# Get binding details (aliases: show, describe)
kestractl bindings get <binding_id>
# Create a binding
kestractl bindings create --role <role_id> --user <user_id>
kestractl bindings create --role <role_id> --group <group_id>
# Create multiple bindings from a JSON file
kestractl bindings bulk-create --file bindings.json
# Delete a binding (alias: rm)
kestractl bindings delete <binding_id># List all invitations
kestractl invitations list
kestractl invitations list --output json
# List invitations for a specific email address
kestractl invitations list-by-email user@example.com
# Get an invitation
kestractl invitations get <invitation_id>
# Create an invitation
kestractl invitations create --email user@example.com --role <role_id>
# Delete an invitation (alias: rm)
kestractl invitations delete <invitation_id># Table output (default, human-readable)
kestractl flows list my.namespace
# JSON output (for scripting)
kestractl flows list my.namespace --output json# Override config settings with flags
kestractl flows get my.namespace my-flow \
--host https://kestra.example.com \
--tenant production \
--token YOUR_TOKEN
# Or use environment variables
KESTRACTL_HOST=https://kestra.example.com \
KESTRACTL_TENANT=production \
KESTRACTL_TOKEN=YOUR_TOKEN \
kestractl flows list my.namespacekestractl uses a simple, direct architecture built on Cobra, Viper, and the official Kestra Go SDK.
main.go → root.go → commands → Client → Kestra SDK → Kestra API
Configuration follows the 12-factor app methodology:
- Viper handles configuration from multiple sources (flags, env vars, config file)
- Clear precedence order ensures predictable behavior
- Flags are bound to Viper automatically via
PersistentPreRunE
kestractl/
├── main.go # Entrypoint - calls cli.Execute()
├── go.mod # Dependencies: cobra, viper, kestra SDK, yaml
└── src/cli/
├── root.go # Root command, global flags, Viper initialization
├── client.go # Client wrapper for SDK with Viper config resolution
├── client_test.go
├── auth.go # AuthManager - ~/.kestractl/config.yaml persistence
├── auth_test.go
├── render.go # Renderer: table or JSON output
├── render_test.go
├── telemetry.go # PostHog event per command (disable via env var)
├── telemetry_test.go
├── config.go # Config subcommands (add, show, use, remove)
├── flows.go # Flows commands
├── flows_test.go
├── executions.go # Executions commands
├── executions_test.go
├── triggers.go # Triggers commands
├── triggers_test.go
├── namespaces.go # Namespaces commands
├── namespaces_test.go
├── kv.go # KV store commands (list, get, set, update, delete)
├── kv_test.go
├── nsfiles.go # Namespace files commands
├── nsfiles_test.go
├── plugins.go # Plugins commands (download, list)
├── plugins_test.go
├── workers.go # Workers commands (registration-tokens generate)
├── workers_test.go
├── dashboards.go # Dashboards commands (EE)
├── dashboards_test.go
├── apps.go # Apps commands (EE)
├── apps_test.go
├── assets.go # Assets commands (EE)
├── assets_test.go
├── blueprints.go # Blueprints commands (community + internal EE)
├── blueprints_test.go
├── test_suites.go # Test suites commands (EE)
├── test_suites_test.go
├── users.go # IAM users commands (EE)
├── users_test.go
├── groups.go # IAM groups commands (EE)
├── groups_test.go
├── roles.go # IAM roles commands (EE)
├── roles_test.go
├── service_accounts.go # IAM service accounts commands (EE)
├── service_accounts_test.go
├── bindings.go # IAM role bindings commands (EE)
├── bindings_test.go
├── invitations.go # IAM invitations commands (EE)
├── invitations_test.go
└── testdata/ # Test fixtures
└── flow.yaml
| Decision | Rationale |
|---|---|
| Direct SDK calls | No unnecessary abstraction layers. Commands call the SDK directly through a thin Client wrapper. |
| 12-factor config with Viper | Viper handles flags > env vars > config file precedence automatically. Clean, predictable config resolution. |
| YAML config format | Human-readable, supports multiple contexts, industry standard (similar to kubectl, docker, etc.). |
| Pure functions for logic | Business logic in testable run*() functions separate from Cobra command wiring. |
| Minimal test mocking | Tests focus on pure functions and argument validation. Integration tests for SDK calls. |
go build ./...
./kestractl --helpgo test ./src/...See CONTRIBUTING.md for detailed instructions on adding new commands.
- Go 1.25 or newer
- Access to a Kestra instance and API token