diff --git a/src/gitlab-tofu.sh b/src/gitlab-tofu.sh
index b552713ca1c12670fc5095061fe138533dd86eef..1d4eb464f26e68a1a956a64f77aedc3024a8131d 100644
--- a/src/gitlab-tofu.sh
+++ b/src/gitlab-tofu.sh
@@ -237,9 +237,14 @@ if [ $sourced -eq 0 ]; then
       terraform_init "${@}"
     ;;
     "plan")
+      plan_args=''
+      if [ "${OPENTOFU_COMPONENT_USE_DETAILED_EXITCODE}" = 'true' ]; then
+        plan_args='-detailed-exitcode'
+      fi
+
       $TF_IMPLICIT_INIT && terraform_init
       # shellcheck disable=SC2086
-      tofu "${TF_CHDIR_OPT}" "${@}" -input=false -out="${TF_PLAN_CACHE}" ${var_file_args}
+      tofu "${TF_CHDIR_OPT}" "${@}" -input=false -out="${TF_PLAN_CACHE}" ${var_file_args} ${plan_args}
     ;;
     "plan-json")
       tofu "${TF_CHDIR_OPT}" show -json "${TF_PLAN_CACHE}" | \
diff --git a/templates/plan.yml b/templates/plan.yml
index b08502ab78490f2bf3c66b23177cef59132702b1..c10d2d36b04fdd9c8afa88deaa0a3ef5b29c2a72 100644
--- a/templates/plan.yml
+++ b/templates/plan.yml
@@ -99,11 +99,31 @@ spec:
       default: pull-push
       type: string
       description: 'Defines the cache policy of the job.'
+    warning_on_none_empty_plan:
+      default: false
+      type: boolean
+      description: 'Whether to mark the job with a warning if the plan contains a diff.'
 
 ---
 
+# NOTE: the two following jobs are necessary to implement the abstraction logic
+# required for the `warning_on_none_empty_plan` input.
+# Without any kind of flow control support for the GitLab CI YAML we cannot infer
+# another value from the input. However, we can clearly apply "inheritance" to
+# customize behavior related to the CI keywords that have otherwise nothing
+# in common with the inputs value.
+'.$[[ inputs.as ]]:detailed_exitcode:warning:false':
+  extends: null
+
+'.$[[ inputs.as ]]:detailed_exitcode:warning:true':
+  allow_failure:
+    exit_codes: [2]
+
 '$[[ inputs.as ]]':
   stage: $[[ inputs.stage ]]
+  extends:
+    # NOTE: see the comment above. This is to support the `warning_on_none_empty_plan` input.
+    - '.$[[ inputs.as ]]:detailed_exitcode:warning:$[[ inputs.warning_on_none_empty_plan ]]'
   environment:
     name: $[[ inputs.state_name ]]
     action: prepare
@@ -131,6 +151,11 @@ spec:
     TF_STATE_NAME: $[[ inputs.state_name ]]
     TF_PLAN_NAME: $[[ inputs.plan_name ]]
     OPENTOFU_COMPONENT_VAR_FILE: '$[[ inputs.var_file ]]'
+    OPENTOFU_COMPONENT_USE_DETAILED_EXITCODE: '$[[ inputs.warning_on_none_empty_plan ]]'
+    # NOTE: we rely on correct exitcode reporting behavior for the `warning_on_none_empty_plan` input
+    # behavior. However, when using bash the runner does not work properly without setting
+    # the feature flag below to `true`.
+    FF_USE_NEW_BASH_EVAL_STRATEGY: 'true'
   image:
     name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]$[[ inputs.image_digest ]]'
   script:
diff --git a/tests/integration-tests/WarningOnNoneEmptyPlan.gitlab-ci.yml b/tests/integration-tests/WarningOnNoneEmptyPlan.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1c3fbf5ef9d2685d28aa2c98dcf00e97d09fddfa
--- /dev/null
+++ b/tests/integration-tests/WarningOnNoneEmptyPlan.gitlab-ci.yml
@@ -0,0 +1,36 @@
+include:
+  - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/plan@$CI_COMMIT_SHA
+    inputs:
+      image_registry_base: $GITLAB_OPENTOFU_IMAGE_BASE
+      version: $CI_COMMIT_SHA
+      base_os: $GITLAB_OPENTOFU_BASE_IMAGE_OS
+      opentofu_version: $OPENTOFU_VERSION
+      root_dir: $TEST_TF_ROOT
+      state_name: $TEST_TF_STATE_NAME
+      warning_on_none_empty_plan: true
+
+  # For CI Terraform state cleanup
+  - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/delete-state@$CI_COMMIT_SHA
+    inputs:
+      state_name: $TEST_TF_STATE_NAME
+      rules: [{when: always}]
+
+stages: [build, cleanup, verify]
+
+verify:plan-job:has-warning-state:
+  stage: verify
+  needs: ['plan']
+  rules: [{when: always}]
+  image: alpine:latest
+  before_script:
+    - apk add --update curl jq
+  script:
+    - |
+      endpoint="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs"
+      is_warning_job=$(curl --silent "$endpoint" | jq -r '.[] | select(.name == "plan") | [.status == "failed", .allow_failure == true] | all')
+      if [ "$is_warning_job" != 'true' ]; then
+        echo 'Error: the plan job was not in warning state.'
+        exit 1
+      else
+        echo 'Success: the plan job was in warning state.'
+      fi
diff --git a/tests/integration.gitlab-ci.yml b/tests/integration.gitlab-ci.yml
index af76bcbdec8f316bea3f05fc6bac6a34f7fd49d7..90e8bc1b7a8208b7f188b652a19aefd0f3d04204 100644
--- a/tests/integration.gitlab-ci.yml
+++ b/tests/integration.gitlab-ci.yml
@@ -16,6 +16,7 @@ component:
           - ModuleRelease
           - Destroy
           - VarFile
+          - WarningOnNoneEmptyPlan
         GITLAB_OPENTOFU_BASE_IMAGE_OS:
           - alpine
           - debian