Configure Plugins, Static Policies, Retries & System Flows

For the complete documentation index, see llms.txt. For a full content snapshot, see llms-full.txt. Append .md to any kestra.io/docs/* URL for plain Markdown.

Use this page when configuring how tasks, plugins, and execution-time behaviors work across your Kestra instance.

Plugins

This section is about how Kestra discovers and distributes plugin code. If a task type is missing, a plugin version needs to be pinned, or your organization uses a private artifact source, start here.

This area includes:

  • installing plugins
  • custom Maven repositories
  • Enterprise plugin repositories
  • static policies for installation-wide defaults and enforcement (Enterprise Edition)
  • plugin security and allowed plugins
  • plugin management settings

For many teams, this is the most important section after runtime setup because it centralizes behavior shared across many flows.

Install kestractl, then download plugins with kestractl plugins and copy or mount the JARs into the Kestra plugins directory:

kestractl plugins get io.kestra.plugin:plugin-script-python --compatible-for <version>

See Install Selected Plugins on a Slim Kestra Image for the full workflow. From inside a Kestra image, the server CLI can also install plugins directly with kestra plugins install.

The repositories below are used when the Kestra server downloads plugins itself, for example with kestra plugins install or Versioned Plugins. kestractl takes its repository and credentials as flags instead.

Add custom repositories:

kestra:
plugins:
repositories:
central:
url: https://repo.maven.apache.org/maven2/
google-artifact-registry:
url: https://${GCP_REGISTRY_LOCATION}-maven.pkg.dev/${GCP_PROJECT_ID}/${GCP_REPOSITORY}
basic-auth:
username: oauth2accesstoken
password: ${GCP_OAUTH_ACCESS_TOKEN}

Install EE plugins from the Kestra registry:

kestra:
plugins:
repositories:
kestra-io:
url: https://registry.kestra.io/maven
basic-auth:
username: ${kestra.ee.license.id:}
password: ${kestra.ee.license.fingerprint:}

Most teams only need custom repositories if they publish private plugins or mirror public artifacts through an internal registry.

Static policies (global defaults and enforcement)

In Kestra 2.0, global plugin defaults are replaced by static policies declared under kestra.policies in server configuration. Static policies form the outermost scope, apply across all tenants, and cannot be overridden through the API.

Apply an installation-wide default that flows can still override:

kestra:
policies:
- id: global-log-level
description: "Default log level for all Log tasks."
rules:
- type: io.kestra.plugin.ee.rules.Add
on: PLUGIN
where:
- field: type
operator: EQUAL_TO
value: io.kestra.plugin.core.log.Log
values:
level: ERROR

Enforce a value that tasks cannot override (override: true):

kestra:
policies:
- id: enforce-docker-isolation
description: "Force Docker task runner for all shell script tasks."
rules:
- type: io.kestra.plugin.ee.rules.Add
on: PLUGIN
override: true
where:
- field: type
operator: STARTS_WITH
value: io.kestra.plugin.scripts.shell
values:
containerImage: ubuntu:latest
taskRunner:
type: io.kestra.plugin.scripts.runner.docker.Docker

Static policies are evaluated by the Executor and propagated to all components, so every server should have the same kestra.policies configuration. A malformed static policy prevents server startup (fail-closed) — validate in a staging environment first.

Precedence works as follows:

  • Static policies (kestra.policies) form the outermost scope
  • Tenant-level and namespace-level Policies apply inside that
  • Task properties fill any remaining unset values
  • override: true on a policy rule always wins over the author’s value

Use override: false (the default) for convenience defaults and override: true when the platform must enforce a value such as a specific task runner.

Enable or preconfigure plugin features globally:

kestra:
plugins:
configurations:
- type: io.kestra.plugin.core.flow.Subflow
values:
outputs:
enabled: true
- type: io.kestra.plugin.core.trigger.Schedule
values:
recoverMissedSchedules: NONE

You can also enable Docker task-runner volume mounting:

kestra:
plugins:
configurations:
- type: io.kestra.plugin.scripts.runner.docker.Docker
values:
volumeEnabled: true

The examples in this section do different jobs: defaults applies reusable task values, while configurations enables or tunes plugin features that are not always expressed directly in a flow.

Plugin security and management

This section becomes relevant once you want governance over what can be installed or when plugin lifecycle is managed centrally instead of manually on each instance.

In Enterprise Edition, you can restrict which plugins are allowed:

kestra:
plugins:
security:
includes:
- io.kestra.*
excludes:
- io.kestra.plugin.core.debug.Echo

Managed plugins are configured under kestra.plugins.management:

kestra:
plugins:
management:
enabled: true
remote-storage-enabled: true
custom-plugins-enabled: true
local-repository-path: /tmp/kestra/plugins-repository
auto-reload-enabled: true
auto-reload-interval: 60s
default-version: LATEST
worker-access: STORAGE # EE only: STORAGE (default) or CONTROLLER
  • remote-storage-enabled: store managed plugins in internal storage rather than on local disk
  • auto-reload-enabled / auto-reload-interval: check for updated plugins on a fixed interval
  • default-version: controls which plugin version is selected when no explicit version is pinned; accepts LATEST, CURRENT, OLDEST, NONE, or a specific version string
  • worker-access (EE): controls how workers fetch managed plugin artifacts. Set to CONTROLLER when a worker runs with dedicated storage, separate from the internal storage that the webserver and Worker Controller use. See Dedicated-storage workers.

Execution behavior

These settings affect how the platform behaves around tasks and executions globally. Use them for platform-wide operational defaults, not for flow-specific logic.

This part of the configuration also includes:

  • retries
  • temporary task storage
  • HTTP task URL filtering
  • tutorial flows
  • system flows
  • local flow synchronization
  • enabling templates

Global retries for internal storage and secret-manager calls:

kestra:
retries:
attempts: 5
delay: 1s
max-delay: ~
multiplier: 2.0

max-delay caps the maximum backoff interval. It is undefined by default, which means the delay grows without bound according to the multiplier.

Example task-level retry:

tasks:
- id: fetch
type: io.kestra.plugin.core.http.Request
uri: https://example.com/api
retry:
type: constant
interval: PT5M
maxDuration: PT1H
maxAttempts: 3
warningOnRetry: true

That distinction matters: kestra.retries protects platform integrations such as storage and secret backends, while task retry behavior belongs in the flow. See Retries for task-level and flow-level options. In Enterprise Edition, a Policy can add a flow-level retry to every flow in a namespace or tenant.

Use kestra.tasks.tmp-dir when task runners need a predictable working directory on the host or inside a mounted volume:

kestra:
tasks:
tmp-dir:
path: /tmp/kestra-wd/tmp

Ensure your container or VM volume mounts align with that path:

volumes:
- kestra-data:/app/storage
- /var/run/docker.sock:/var/run/docker.sock
- /home/kestra:/home/kestra

HTTP task URL filtering

Use kestra.tasks.http to restrict which URLs HTTP plugin tasks can call. Configure an allow-list, a deny-list, or both:

kestra:
tasks:
http:
allowed-list:
- https://api.example.com
denied-list:
- http://169.254.169.254
- http://localhost
KeyDefaultDescription
kestra.tasks.http.allowed-list[]When non-empty, a request URI must match at least one entry or the task fails.
kestra.tasks.http.denied-list[]A request URI that matches any entry causes the task to fail. Evaluated after the allowed-list.

For security guidance and matching behavior, see HTTP task URL filtering.

Reserve system for background workflows, or rename it if your organization already uses that namespace for something else:

kestra:
system-flows:
namespace: system

Disable tutorial flows outside trial or demo environments:

kestra:
tutorial-flows:
enabled: false

Templates are deprecated and disabled by default, but can still be re-enabled for migration work:

kestra:
templates:
enabled: true
micronaut:
io:
watch:
enabled: true
paths:
- /path/to/your/flows

Use Micronaut file watching only when you want local flow synchronization from disk into Kestra.

Variables and rendering

These settings influence expression rendering across the whole instance. They are linked here because they affect execution-time behavior, but they are documented in more depth on the runtime page.

Relevant runtime-wide settings include:

  • environment variable prefixes
  • global variables
  • recursive rendering
  • template cache

Those settings are documented in more detail on Runtime and Storage, since they affect the whole instance and not just plugin behavior.

Subflow function configuration

The subflow() Pebble function, used to populate SELECT and MULTISELECT input dropdowns at form render time, has three configurable limits. All three accept ISO 8601 duration strings or integers.

kestra:
pebble:
subflow-function:
default-timeout: PT1M # timeout when the caller omits the timeout argument
max-timeout: PT5M # hard cap — larger values are rejected at runtime
max-depth: 3 # maximum nesting depth of subflow() calls on one render thread
KeyDefaultDescription
kestra.pebble.subflow-function.default-timeoutPT1MApplied when the timeout argument is not passed. Keep this short — the call blocks the Execute form render.
kestra.pebble.subflow-function.max-timeoutPT5MHard cap. A timeout argument larger than this value is rejected at runtime with an error.
kestra.pebble.subflow-function.max-depth3Guards against runaway recursion. A subflow whose own inputs also call subflow() counts against this limit.

Increase max-timeout only if your data-fetching subflows genuinely need longer — long form renders degrade user experience. Increase max-depth only if you have intentionally nested multi-level dependent dropdowns.

Was this page helpful?