Tasks are in prerelease. To request this feature on your project, open this prepopulated support ticket and add your project ID before submitting.
.upsun/config.yaml.
When triggered, a task container is injected into your environment’s cluster, runs a single command, and is removed when the command exits.
When to use a task
A task is the right choice when you need:- A background AI agent session — for example, an agent that reads your codebase, calls tools such as shell commands or database queries, and writes the results back to your project.
- A one-time job that needs service access: database maintenance, a data export, a report.
- A batch job triggered from your application rather than on a schedule.
- A long-running daemon: use a worker.
- A scheduled job: use a cron.
- Serving HTTP traffic: tasks are not routable and cannot be used as an upstream in
routes:.
How tasks compare to other workloads
| Application | Worker | Cron | Task | |
|---|---|---|---|---|
| Lifecycle | Always running | Always running | Scheduled, run-to-completion | On-demand, run-to-completion |
| HTTP exposure | Yes | No | No | No |
| Has its own image/build | Yes | No (shares app slug) | No (shares app slug) | Yes |
| Triggered by | Deploy | Deploy | Schedule | API call |
| Blocks deployments | N/A | N/A | Cancelled on deploy | Cancelled on deploy |
Define a task
Tasks are declared at the top level of.upsun/config.yaml, alongside applications: and services:.
Required fields
| Field | Description |
|---|---|
type | The runtime image; same syntax as an application and the type in the preceding example. |
run.command | The command to execute. Runs to completion, not as a daemon. To run initialization steps that need service access, place them at the start of this command — for example: node setup.js && node agent.js. |
Common optional fields
| Field | Description |
|---|---|
source.root | Subdirectory containing the task’s code. Defaults to /. |
run.timeout | Maximum duration in seconds. Defaults to 3600 (one hour); max value 86400 (one day). On timeout, the platform sends SIGTERM, then SIGKILL after a grace period. |
authorizations | Declared on a task: API permissions granted to the task container at runtime. Declared on an application: grants the app permission to trigger tasks and call the environment API. |
hooks.build | Command run during the environment build phase, producing a slug reused across runs. |
relationships | Connections to services and applications in the same cluster. |
mounts | Writable directories. instance and tmp mounts are reset between runs; use a storage or service mount to persist data across runs. |
variables | Environment variables defined in your config file. Only use this for non-sensitive values — set secrets such as passwords and API keys using the API or CLI to keep them out of version control, for example: upsun variable:create --name MY_SECRET --sensitive 1. |
Fields that don’t apply
web, workers, and crons have no meaning for tasks. Tasks have no HTTP router, are not long-running, and are not scheduled.
Relationships
A task can declare relationships to applications and services in the same environment: Inside the task container, these relationships appear inPLATFORM_RELATIONSHIPS exactly as they do for applications.
The task can read from the database, write to the cache, and POST results back to the app over HTTP.
Relationship direction is one-way.
Applications and other tasks cannot declare a relationship to a task, because a task exists in the cluster only while a task is running.
If you need the app to receive results from a task, the task should push them to the app, for example by using the app: “myapp:http” relationship.
Trigger a task
Tasks are triggered through the Upsun API (see the task run endpoint reference):variables object in the request body:
$TOKEN is a short-lived access token obtained from your API token. See Authentication for the exchange process and API tokens for the steps to create one.
Each invocation creates an activity (the same mechanism used for deploys, backups, and crons) that gives you:
- A unique activity ID.
- Live status (
pending,in_progress,complete,cancelled). - Streamed logs through the existing activity logs endpoint.
- Cancellation through the
/cancelendpoint on the activity.
Trigger from application code
Declare which tasks the app is allowed to trigger using workload authorizations (theauthorizations key), then request a short-lived token at runtime — no long-lived credentials required.
Steps 1–3 break down each part individually. For a complete implementation combining token retrieval, caching, and triggering, see Sample implementation.
1. Declare the authorization
2. Request a token and trigger the task
3. Cache the token
Token caching is highly recommended if your application triggers tasks repeatedly. Without token caching, every trigger makes a round-trip to the auth proxy. Request a new token only when the current one is about to expire. By default, tokens expire after 60 seconds. Thex-token-ttl header extends the lifetime up to 900 seconds (15 minutes) — set it to match your expected time between task triggers. For example, if your app triggers a task every 5 minutes (300 seconds), set x-token-ttl to slightly more than the trigger interval to account for network delays.
Sample implementation
The following examples combine steps 1–3 into a single helper that handles authorization declaration, token retrieval, caching, and task triggering.Resources, variables, and access
Tasks follow the same model as applications:- Resources (CPU, memory): configured by using
upsun resources:setagainst the task name. Billing is per-second for the duration of each run. - Variables and secrets: configured with
upsun variable:create --level environmentor by using the API. Sensitive variables are injected as environment variables at run time. - Access: standard project roles apply. Project admins and contributors can change task definitions, trigger tasks, and view runs.
Security
Tasks run in the same Linux Containers (LXC) as applications, with the same namespace isolation, capability dropping (removing unnecessary Linux process privileges), seccomp profile, cgroup limits, and network isolation. Cross-project isolation and relationship-based access control apply unchanged. For details, see the Project isolation topic. For tasks that run untrusted code (for example, an LLM-driven agent), consider pairing with bubblewrap inside the task container to restrict filesystem access, environment variables, and syscalls visible to the agent process.Known limitations
- Cancelled on deploy. A running task receives
SIGTERMbefore any deploy on the same environment, followed bySIGKILLafter a grace period of a few seconds. CatchSIGTERM, persist state to a service, and exit cleanly. The caller is responsible for retrying. - Concurrency cap. Multiple task runs can execute in parallel up to a default limit of 3. Further triggers queue behind running ones.
- No task-to-task relationships. Nothing can declare a relationship to a task. An app and a task can share a relationship to the same service or a network file mount.
- Fresh filesystem every run.
instanceandtmpmounts are reset between runs. Use astorageorservicemount for files that must survive across runs. - Requires at least one application. A project with only tasks and services is not currently valid.
- Minimal Console and CLI support. Task activities appear in the activity feed, but there is no dedicated task UI as part of this Prerelease program.