New to Kestra?
Use blueprints to kickstart your first workflows.
Gate deployments with Liquibase validate and status in Kestra. Capture exit codes, block the release on broken or unapplied changelogs, and alert Slack.
Deploying application code on top of a broken or half-applied database migration is how ordinary releases become incidents. This blueprint puts a gate in front of the deploy: io.kestra.plugin.liquibase.CLI runs liquibase validate to prove the changelog is well formed and liquibase status --verbose to check whether unapplied change sets remain, converts both results into task outputs, and fails the execution with a Slack alert when either check is unhealthy. A pipeline that waits on this flow gets a hard stop instead of a hopeful green light.
check_migrations (io.kestra.plugin.liquibase.CLI) receives the changelog through inputFiles and connects using the standard Liquibase environment variables filled from Kestra secrets.liquibase validate runs first with its exit code captured through a shell || fallback, so a broken changelog is recorded rather than aborting the script. liquibase status --verbose then writes the pending-changes report, and a grep for the up-to-date marker turns it into a numeric flag.{{ outputs.check_migrations.vars.validate_exit }} and {{ outputs.check_migrations.vars.pending }}.gate (io.kestra.plugin.core.flow.If) checks both outputs. On failure it posts the reason to Slack, then io.kestra.plugin.core.execution.Fail fails the execution. On success, a Log task records the green light.errors block alerts separately when the gate itself cannot run, because an unverifiable migration state should also block the deploy.The Liquibase commands are one-liners, but a gate is more than commands: exit codes must survive the shell, the pass and fail paths must diverge, someone must be told why a deploy stopped, and the whole decision must be auditable later. Kestra's output protocol carries the shell results into flow logic, the If and Fail tasks make the decision explicit, and every gate decision lives in the execution history next to the release it protected.
DB_URL secret to jdbc:h2:file:./demo-db with username sa and an empty password. Note that a fresh H2 file starts empty, so the demo shows the gate blocking on pending changes, which is the interesting path. For production, use your real JDBC URL, such as jdbc:postgresql://db-host:5432/app.DB_URL: JDBC URL of the target database.DB_USERNAME: database username.DB_PASSWORD: database password.SLACK_WEBHOOK_URL: Slack incoming webhook URL.io.kestra.plugin.core.flow.Subflow so the gate, the migration, and the deploy live in one parent flow.pending check into a Slack-only branch.namespaceFiles synced from Git so the gate always validates the changelog that will actually ship.