diff --git a/templates/validate-plan-destroy.yml b/templates/validate-plan-destroy.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7593c8f5f085930a868eb3efd5e98d55b57c28aa
--- /dev/null
+++ b/templates/validate-plan-destroy.yml
@@ -0,0 +1,113 @@
+spec:
+  inputs:
+    # Stages
+    stage_validate:
+      default: 'validate'
+      description: 'Defines the validate stage. This stage includes the `fmt` and `validate` jobs.'
+    stage_build:
+      default: 'build'
+      description: 'Defines the build stage. This stage includes the `plan` job.'
+    stage_cleanup:
+      default: 'cleanup'
+      description: 'Defines the cleanup stage. This stage includes the `destroy` and `delete-state` jobs.'
+
+    # Versions
+    # This version is only required, because we cannot access the context of the component,
+    # see https://gitlab.com/gitlab-org/gitlab/-/issues/438275
+    version:
+      default: 'latest'
+      description: 'Version of this component. Has to be the same as the one in the component include entry.'
+
+    opentofu_version:
+      default: '1.7.1'
+      options:
+        - '$OPENTOFU_VERSION'
+        - '1.7.1'
+        - '1.7.0'
+        - '1.7.0-alpha1'
+        - '1.6.2'
+        - '1.6.1'
+        - '1.6.0'
+      description: 'OpenTofu version that should be used.'
+
+    # Images
+    image_registry_base:
+      default: '$CI_REGISTRY/components/opentofu'
+      description: 'Host URI to the job images. Will be combined with `image_name` to construct the actual image URI.'
+    # FIXME: not yet possible because of https://gitlab.com/gitlab-org/gitlab/-/issues/438722
+    # gitlab_opentofu_image:
+    #   # FIXME: This should reference the component tag that is used.
+    #   #        Currently, blocked by https://gitlab.com/gitlab-org/gitlab/-/issues/438275
+    #   # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.opentofu_version ]]'
+    #   default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]'
+    #   description: 'Tag of the gitlab-opentofu image.'
+
+    image_name:
+      default: 'gitlab-opentofu'
+      description: 'Image name for the job images. Hosted under `image_registry_base`.'
+
+    # Configuration
+    root_dir:
+      default: ${CI_PROJECT_DIR}
+      description: 'Root directory for the OpenTofu project.'
+    state_name:
+      default: default
+      description: 'Remote OpenTofu state name.'
+    auto_destroy:
+      default: false
+      type: boolean
+      description: 'Whether the destroy job is manual or automatically run.'
+
+---
+
+include:
+  - local: '/templates/fmt.yml'
+    inputs:
+      as: 'fmt'
+      stage: $[[ inputs.stage_validate ]]
+      version: $[[ inputs.version ]]
+      opentofu_version: $[[ inputs.opentofu_version ]]
+      image_registry_base: $[[ inputs.image_registry_base ]]
+      image_name: $[[ inputs.image_name ]]
+      root_dir: $[[ inputs.root_dir ]]
+  - local: '/templates/validate.yml'
+    inputs:
+      as: 'validate'
+      stage: $[[ inputs.stage_validate ]]
+      version: $[[ inputs.version ]]
+      opentofu_version: $[[ inputs.opentofu_version ]]
+      image_registry_base: $[[ inputs.image_registry_base ]]
+      image_name: $[[ inputs.image_name ]]
+      root_dir: $[[ inputs.root_dir ]]
+      state_name: $[[ inputs.state_name ]]
+  - local: '/templates/plan.yml'
+    inputs:
+      as: 'plan'
+      stage: $[[ inputs.stage_build ]]
+      version: $[[ inputs.version ]]
+      opentofu_version: $[[ inputs.opentofu_version ]]
+      image_registry_base: $[[ inputs.image_registry_base ]]
+      image_name: $[[ inputs.image_name ]]
+      root_dir: $[[ inputs.root_dir ]]
+      state_name: $[[ inputs.state_name ]]
+      destroy: true
+  - local: '/templates/destroy.yml'
+    inputs:
+      as: 'destroy'
+      stage: $[[ inputs.stage_cleanup ]]
+      version: $[[ inputs.version ]]
+      opentofu_version: $[[ inputs.opentofu_version ]]
+      image_registry_base: $[[ inputs.image_registry_base ]]
+      image_name: $[[ inputs.image_name ]]
+      root_dir: $[[ inputs.root_dir ]]
+      state_name: $[[ inputs.state_name ]]
+      auto_destroy: $[[ inputs.auto_destroy ]]
+  - local: '/templates/delete-state.yml'
+    inputs:
+      as: 'delete-state'
+      stage: $[[ inputs.stage_cleanup ]]
+      state_name: $[[ inputs.state_name ]]
+
+# NOTE: we have to define this `needs` here, because inputs don't support arrays, yet.
+delete-state:
+  needs: [destroy]
diff --git a/tests/integration-tests/Destroy.gitlab-ci.yml b/tests/integration-tests/Destroy.gitlab-ci.yml
index 0c89d9f65d15267f044165b0bf990fd65f3376e5..2b8ac40f18584416a65c4e0d27c839cb0d90bc05 100644
--- a/tests/integration-tests/Destroy.gitlab-ci.yml
+++ b/tests/integration-tests/Destroy.gitlab-ci.yml
@@ -1,16 +1,28 @@
 include:
-  - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/plan@$CI_COMMIT_SHA
+  - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/validate-plan-destroy@$CI_COMMIT_SHA
     inputs:
       image_registry_base: $GITLAB_OPENTOFU_IMAGE_BASE
       version: $CI_COMMIT_SHA
       opentofu_version: $OPENTOFU_VERSION
       root_dir: $TEST_TF_ROOT
       state_name: $TEST_TF_STATE_NAME
-      destroy: true
 
-stages: [build]
+stages: [validate, build, cleanup]
 
 # Required to run everything immediately, instead of manually.
 
+fmt:
+  rules: [{when: always}]
+
+validate:
+  rules: [{when: always}]
+
 plan:
   rules: [{when: always}]
+
+destroy:
+  rules: [{when: always}]
+
+delete-state:
+  rules: [{when: always}]
+