New to Kestra?
Use blueprints to kickstart your first workflows.
Spin up a Terragrunt preview stack, run checks, and guarantee teardown with a Kestra finally block. run-all destroy runs even when the tests fail.
Preview environments are only cheap when they reliably disappear. This blueprint applies a Terragrunt preview folder, runs a placeholder test step, and then destroys the stack from a finally block, the part of a Kestra flow that runs whether the tasks before it succeeded or failed. The interesting mechanics are in the state handoff: each Kestra task runs in its own container, so the apply task exports its Terraform state files as outputFiles, and the teardown task restores them via inputFiles before running run-all destroy.
To make that handoff deterministic, root.hcl pins state to a predictable path with a remote_state block, state/preview/network/terraform.tfstate and state/preview/app/terraform.tfstate, instead of letting it live inside Terragrunt's cache directories. The demo modules only create local_file resources, so the whole lifecycle runs without cloud credentials.
apply_preview (io.kestra.plugin.terragrunt.cli.TerragruntCLI) materializes the repo from inputFiles and runs terragrunt run-all apply --non-interactive --working-dir live/preview, bringing up both preview units.remote_state block in root.hcl writes each unit's state under a top-level state/ folder, and the task exports those files with outputFiles: state/**/*.tfstate.run_preview_checks is a placeholder Log task standing in for your real test suite against the preview stack.finally block, teardown_when_applied (io.kestra.plugin.core.flow.If) checks that the apply actually exported state, then destroy_preview recreates the same repo layout, restores both state files through inputFiles, and runs terragrunt run-all destroy --non-interactive.errors block posts a Slack alert on any failure, noting that teardown already ran.outputFiles and inputFiles.Shell scripts implement this pattern with trap, until the runner dies, the step times out, or someone ctrl-c's the pipeline. Kestra's finally block is a first-class flow construct: it runs server-side regardless of upstream task state, its guard condition is declarative, and the execution history shows the apply, the checks, and the destroy as separate, individually logged tasks. The state handoff through Kestra's internal storage also means no shared runner disk is required between steps.
root.hcl, then the teardown task no longer needs the state file handoff, and pass provider credentials through task env from {{ secret('...') }}.SLACK_WEBHOOK_URL: Slack incoming webhook URL.SLACK_WEBHOOK_URL secret to your Kestra namespace.Log task with a failing script, and confirm the destroy still runs.run_preview_checks with a real test runner, an HTTP health check task, or a container running your end-to-end suite.root.hcl, then drop the state entries from the teardown task's inputFiles, the backend becomes the handoff.tofu and the TERRAGRUNT_TFPATH environment variable in the task env.