Skip to content

Elevating IaC Workflows with Spacelift Stacks and Dependencies 🛠️

Register for the July 23 demo →


While tasks enjoy the privilege of having their own GUI screen, they're just another type of run. The core difference is that after the common initialization phase, a task will run your custom command instead of a string of preordained vendor-specific commands.

The purpose of tasks»

The main purpose of task is to perform arbitrary changes to your infrastructure in a coordinated, safe and audited way. Tasks allow ultimate flexibility and can be used to check the environment (see the humble ls -la on the above screenshot), perform benign read-only operations like showing parts of the Terraform state, or even make changes to the state itself, like tainting a resource.

Given that thanks to the Docker integration you have full control over the execution environment of your workloads, there's hardly a limit to what you can do.


Obvious abuse of shared workers will get you kicked out of the platform. But you can abuse private workers all you like.

With the above caveat, let's go through the main benefits of using Spacelift tasks.


Tasks are always treated as operations that may change the underlying state, and are thus serialized. No two tasks will ever run simultaneously, nor will a task execute while a tracked run is in progress. This prevents possible concurrent updates to the state that would be possible without a centrally managed mutex.

What's more, some tasks will be more sensitive than others. While a simple ls is probably nothing to be afraid of, the two-way state migration described above could have gone wrong in great many different ways. The stack locking mechanism thus allows taking exclusive control over one or more stacks by a single individual, taking the possibility of coordination to a whole new level.


Any non-trivial infrastructure project will inevitably be full of credentials and secrets which are possibly too sensitive to be stored even on a work laptop. Tasks allow any operation to be executed remotely, preventing the leak of sensitive data.

Spacelift's integration with infra providers like AWS also allows authentication without any credentials whatsoever, which further protects you from the shame and humiliation of having the keys to the kingdom leaked by running the occasional env command, as you do. Actually, let's run it in Spacelift to see what gives:

Yes, the secrets are masked in the output and won't leak due to an honest mistake.


There are limits to the extent we can protect you from a determined attacker with write access to your stack. We don't want to give you a false sense of security where none is warranted. You may want to look into task policies to prevent certain (or even all) tasks from being executed.


Unlike arbitrary operations performed on your local machine, tasks are recorded for eternity, so in cases where some archaeology is necessary, it's easy to see what happened and when. Tasks are attributed to individuals (or API keys) that triggered them and the access model ensures that only stack writers can trigger tasks, giving you even more control over your infrastructure.

Performing a task»

Apart from the common run phases described in the general run documentation, tasks have just one extra state - performing. That's when the arbitrary user-supplied command is executed, wrapped in sh -c to support all the shell goodies we all love to abuse. In particular, you can use as many && and || as you wish.

Performing a task will succeed and the task will transition to the finished state if the exit code of your command is 0 (the Unix standard). Otherwise the task is marked as failed. Performing cannot be stopped since we must assume that it involves state changes.


Tasks are not interactive so you may need to add the -force argument to the command.

Skipping initialization»

In rare cases it may be useful to perform tasks without initialization - like when the initialization would fail without some changes being introduced. An obvious example here are Terraform version migrations. This corner case is served by explicitly skipping the initialization. In the GUI (on by default), you will find the toggle to control this behavior:

Let's execute a task without initialization on an OpenTofu stack:

Notice how the operation failed because it is expected to be executed on an initialized OpenTofu workspace. But the same operation would easily succeed if we were to run it in the default mode, with initialization: