DigitalOcean

DigitalOcean

Certified

Manage DigitalOcean droplets, Kubernetes clusters, databases, load balancers, volumes, snapshots, domains, firewalls, monitoring alert policies, droplet metrics, billing, Spaces access keys, security scans, and CDN endpoints through the DigitalOcean API v2.

How to use the DigitalOcean plugin

This plugin manages DigitalOcean cloud resources (droplets, Kubernetes clusters, databases, load balancers, volumes, snapshots, domains, firewalls, billing, Spaces access keys, security scans, and CDN endpoints) through the DigitalOcean API v2.

Authentication

Every task and the droplet trigger require apiToken, a personal access token sent as Authorization: Bearer <token>. Create one in the DigitalOcean control panel under API > Tokens; it is prefixed dop_v1_. Store it as a Kestra secret and reference it with {{ secret('DIGITALOCEAN_TOKEN') }}, or set it once as a plugin default so every task in a namespace picks it up automatically.

baseUrl defaults to https://api.digitalocean.com and rarely needs to change.

Rate limits

DigitalOcean returns HTTP 429 once the account's rate limit is hit. This plugin surfaces the response's retry-after header value in the error message so a flow's retry configuration can back off accordingly.

Tasks

Tasks are grouped by resource, one package per DigitalOcean resource type. Class names are bare actions (List, Get, Create, Delete, ...), always used with their full package, for example io.kestra.plugin.digitalocean.droplet.Create.

List tasks share the same shape: perPage (defaults to 200, the API maximum) and fetchType (FETCH, FETCH_ONE, STORE, or NONE, defaults to FETCH), following DigitalOcean's page-based pagination automatically and reporting the API's total count regardless of fetchType.

  • droplet: List, Get, Create, Delete, Resize (change size and/or disk), and Action (POWER_ON, POWER_OFF, REBOOT, or SNAPSHOT, the last taking an optional name). Create's ip output is only populated once the droplet is active. DigitalOcean assigns the public IPv4 address a few tens of seconds after creation, so Create waits for that by default (wait: true, waitTimeout: PT5M, pollInterval: PT5S). Set wait: false to return as soon as the API accepts the creation request instead, in which case ip is null.
  • kubernetes: List, Get, Create, Delete, and GetKubeconfig. The kubeconfig contains a client certificate and key, so it is only ever written to Kestra internal storage, never returned as a string output.
  • database: List, Get, Create, Delete, and Resize. Outputs never include the connection user or password, only host and port, to avoid leaking credentials into execution outputs.
  • loadbalancer: List, Get, Create, Update, and Delete. DigitalOcean's update endpoint replaces the full configuration, not a partial patch: Update always requires name, region, and forwardingRules again, even to change a single field.
  • volume: List, Get, Create, Delete, Attach, Detach, Resize, and CreateSnapshot, plus GetAction and ListActions to follow the asynchronous attach, detach and resize actions. Resize only grows a volume (up to 16 TiB) and does not grow the filesystem on it; pass its actionId output to GetAction to check when the resize completes.
  • snapshot: List, Get, and Delete for droplet and volume snapshots (/v2/snapshots). List takes an optional resourceType (DROPLET or VOLUME). Snapshot IDs are kept as strings, since DigitalOcean returns an integer for droplet snapshots and a UUID for volume snapshots.
  • billing: GetBalance, ListBillingHistory, ListInvoices, and ListInvoiceItems, all read-only. GetBalance returns the amounts as numbers (DigitalOcean sends them as strings), so they can be compared in expressions, e.g. {{ outputs.get_balance.monthToDateUsage > 100 }}.
  • domain: List, Get, Create, and Delete for domain zones themselves (/v2/domains), the DNS-hosting equivalent of a droplet or a load balancer: the resource that exists on the account, not the records inside it.
  • domain.record: List, Get, Create, and Delete for DNS records within a zone (/v2/domains/{domain}/records). domain (the zone name, e.g. example.com) is a required property on every task in this package. A zone must already exist (via domain.Create) before records can be added to it. Create's recordType is the RecordType enum (A, AAAA, CAA, CNAME, MX, NS, SRV, TXT); SOA is excluded because DigitalOcean manages a zone's SOA record automatically and does not allow creating one.
  • firewall: List, Get, Create, and Delete.
  • monitoring.alertpolicy: List, Get, Create, Update, and Delete for DigitalOcean monitoring alert policies.
  • monitoring.metrics: DropletCpu, DropletMemory, DropletBandwidth, and DropletDisk for Droplet performance metrics over a time window. Time bounds accept Instant or ISO-8601 strings and are sent as UNIX epoch seconds.
  • spaces.key: List, Get, Create, and Delete for Spaces access keys. Create takes grants, each a bucket and a permission (READ or READWRITE), or a single FULLACCESS grant with no bucket; the two kinds cannot be mixed. DigitalOcean returns the secret key only once, so Create outputs it as an encrypted string (configure Kestra's encryption secret key) and Get/List never include it.
  • security.scan: List, Create, Get, GetLatest, and ListAffectedResources for security (CSPM) scans. Create starts a scan and returns without waiting; poll Get until the status leaves IN_PROGRESS. Get and GetLatest return the scan with one page of findings (up to 200), which can be filtered by severity or findingType; List returns the scans without their findings.
  • cdn: List, Get, Create, Update, Delete, and PurgeCache for CDN endpoints in front of Spaces buckets. ttl is in seconds and must be 60, 600, 3600, 86400, or 604800. PurgeCache takes the paths to purge, relative to the bucket; a path ending in * purges everything under it, and * alone the whole cache.

Kubernetes node pools (kubernetes.Create.nodePools, a NodePool with size, name, count) and load balancer forwarding rules (loadbalancer.Create/Update.forwardingRules, a ForwardingRule with entryProtocol, entryPort, targetProtocol, targetPort, and optional certificateId and tlsPassthrough) are typed classes: write idiomatic camelCase field names in the flow, and each is mapped to DigitalOcean's own JSON keys internally. Firewall's inbound/outbound rules have four different source/destination variants and stay modeled as Property<List<Map<String, Object>>>, following DigitalOcean's own JSON shape directly rather than a dedicated type per variant.

Creating a zone and a record together

id: digitalocean_setup_dns
namespace: company.team

tasks: 
  - id: create_domain
    type: io.kestra.plugin.digitalocean.domain.Create
    apiToken: "{{ secret('DIGITALOCEAN_TOKEN') }}"
    name: "example.com"
    ipAddress: "104.131.186.241"
  - id: create_record
    type: io.kestra.plugin.digitalocean.domain.record.Create
    apiToken: "{{ secret('DIGITALOCEAN_TOKEN') }}"
    domain: "example.com"
    recordType: A
    name: "www"
    data: "104.131.186.241"

Triggers

  • droplet.Trigger: polls the account's droplet list at interval (defaults to PT5M) and fires an execution when a new droplet appears. The first evaluation only establishes the baseline of existing droplet ids and never fires. Only one new droplet is reported per poll; if several droplets appear between polls, the rest are reported on the following polls. Outputs: id, name, region, status, createdAt.

    This trigger is at-least-once: a droplet id missing from a single poll (a transient gap from DigitalOcean's eventual consistency, or a short page) is tolerated for up to 3 consecutive polls before it is dropped from the watermark, so a reappearing droplet does not re-fire. The watermark is stored under a Kestra namespace KV key prefixed digitalocean_droplet_trigger_; do not delete it manually, since doing so re-establishes the baseline and skips whatever is already on the account at that point.