diff --git a/templates/full-pipeline.yml b/templates/full-pipeline.yml
index c61819795650dfb7dbc48b2b63604fcdeab071f7..af0c4ce83da76e9f7433bbd0d64e3800e44c219c 100644
--- a/templates/full-pipeline.yml
+++ b/templates/full-pipeline.yml
@@ -96,6 +96,10 @@ spec:
     plan_artifacts_access:
       default: 'none'
       description: 'Access level for the plan artifact. See https://docs.gitlab.com/ee/ci/yaml/#artifactsaccess for possible values.'
+    plan_extra_artifacts:
+      default: []
+      type: array
+      description: 'Extra artifacts to upload from the plan'
     var_file:
       default: ''
       type: string
@@ -310,6 +314,7 @@ include:
       state_name: $[[ inputs.state_name ]]
       plan_name: $[[ inputs.plan_name ]]
       artifacts_access: $[[ inputs.plan_artifacts_access ]]
+      extra_artifacts: $[[ inputs.plan_extra_artifacts ]]
       var_file: $[[ inputs.var_file ]]
       rules: $[[ inputs.plan_rules ]]
       warning_on_non_empty_plan: $[[ inputs.warning_on_non_empty_plan ]]
@@ -443,6 +448,7 @@ stages:
           state_name: $[[ inputs.state_name]]
           plan_name: $[[ inputs.plan_name ]]
           plan_artifacts_access: $[[ inputs.plan_artifacts_access ]]
+          plan_extra_artifacts: $[[ inputs.plan_extra_artifacts ]]
           var_file: $[[ inputs.var_file ]]
           fmt_allow_failure: $[[ inputs.fmt_allow_failure ]]
           fmt_rules: $[[ inputs.fmt_rules ]]
diff --git a/templates/plan.yml b/templates/plan.yml
index 096db7471c49177efcdf14fdb68a1234cde68856..c708d39bb6d4478dd259476a2df3da9ec9841598 100644
--- a/templates/plan.yml
+++ b/templates/plan.yml
@@ -74,6 +74,10 @@ spec:
     artifacts_access:
       default: 'none'
       description: 'Access level for the plan artifact. See https://docs.gitlab.com/ee/ci/yaml/#artifactsaccess for possible values.'
+    extra_artifacts:
+      default: []
+      type: array
+      description: 'Extra artifacts to upload from the plan'
     var_file:
       default: ''
       type: string
@@ -197,6 +201,7 @@ include:
     access: '$[[ inputs.artifacts_access ]]'
     paths:
       - $GITLAB_TOFU_ROOT_DIR/$[[ inputs.plan_name ]].cache
+      - '$[[ inputs.extra_artifacts ]]'
     reports:
       terraform: $GITLAB_TOFU_ROOT_DIR/$[[ inputs.plan_name]].json
   rules: $[[ inputs.rules ]]
diff --git a/templates/validate-plan-apply.yml b/templates/validate-plan-apply.yml
index 2a358dc4c2923df69e09f2eb7e4db49a108f43ca..e1f05fe6c065f21d0140e64a4a39817263a27e6e 100644
--- a/templates/validate-plan-apply.yml
+++ b/templates/validate-plan-apply.yml
@@ -83,6 +83,10 @@ spec:
     plan_artifacts_access:
       default: 'none'
       description: 'Access level for the plan artifact. See https://docs.gitlab.com/ee/ci/yaml/#artifactsaccess for possible values.'
+    plan_extra_artifacts:
+      default: []
+      type: array
+      description: 'Extra artifacts to upload from the plan'
     var_file:
       default: ''
       type: string
@@ -248,6 +252,7 @@ include:
       state_name: $[[ inputs.state_name ]]
       plan_name: $[[ inputs.plan_name ]]
       artifacts_access: $[[ inputs.plan_artifacts_access ]]
+      extra_artifacts: $[[ inputs.plan_extra_artifacts ]]
       var_file: $[[ inputs.var_file ]]
       rules: $[[ inputs.plan_rules ]]
       cache_policy: pull
@@ -332,6 +337,7 @@ stages:
           state_name: $[[ inputs.state_name]]
           plan_name: $[[ inputs.plan_name ]]
           plan_artifacts_access: $[[ inputs.plan_artifacts_access ]]
+          plan_extra_artifacts: $[[ inputs.plan_extra_artifacts ]]
           var_file: $[[ inputs.var_file ]]
           fmt_rules: $[[ inputs.fmt_rules ]]
           fmt_allow_failure: $[[ inputs.fmt_allow_failure ]]
diff --git a/templates/validate-plan-destroy.yml b/templates/validate-plan-destroy.yml
index 78cd203133192ce795a5ccacfcf23b1aaca650c4..909aeab6000615304d7b7db9b52cde1f00d91717 100644
--- a/templates/validate-plan-destroy.yml
+++ b/templates/validate-plan-destroy.yml
@@ -76,6 +76,10 @@ spec:
     plan_artifacts_access:
       default: 'none'
       description: 'Access level for the plan artifact. See https://docs.gitlab.com/ee/ci/yaml/#artifactsaccess for possible values.'
+    plan_extra_artifacts:
+      default: []
+      type: array
+      description: 'Extra artifacts to upload from the plan'
     # FIXME: at the moment we cannot support this input
     # because we cannot nest inputs: https://gitlab.com/gitlab-org/gitlab/-/issues/438722
     # If you want to auto destroy, please refer to the `rules` input.
@@ -254,6 +258,7 @@ include:
       state_name: $[[ inputs.state_name ]]
       plan_name: $[[ inputs.plan_name ]]
       artifacts_access: $[[ inputs.plan_artifacts_access ]]
+      extra_artifacts: $[[ inputs.plan_extra_artifacts ]]
       destroy: true
       var_file: $[[ inputs.var_file ]]
       rules: $[[ inputs.plan_rules ]]
@@ -364,6 +369,7 @@ stages:
           state_name: $[[ inputs.state_name]]
           plan_name: $[[ inputs.plan_name ]]
           plan_artifacts_access: $[[ inputs.plan_artifacts_access ]]
+          plan_extra_artifacts: $[[ inputs.plan_extra_artifacts ]]
           var_file: $[[ inputs.var_file ]]
           fmt_allow_failure: $[[ inputs.fmt_allow_failure ]]
           fmt_rules: $[[ inputs.fmt_rules ]]
diff --git a/templates/validate-plan.yml b/templates/validate-plan.yml
index 9f7061d90b37a9c65a8c8cff43c217494576aab0..13d424c6a7f95b3c080936e676ed5fe91eaa771c 100644
--- a/templates/validate-plan.yml
+++ b/templates/validate-plan.yml
@@ -73,6 +73,10 @@ spec:
     artifacts_access:
       default: 'none'
       description: 'Access level for the plan artifact. See https://docs.gitlab.com/ee/ci/yaml/#artifactsaccess for possible values.'
+    plan_extra_artifacts:
+      default: []
+      type: array
+      description: 'Extra artifacts to upload from the plan'
     var_file:
       default: ''
       type: string
@@ -232,6 +236,7 @@ include:
       state_name: $[[ inputs.state_name ]]
       plan_name: $[[ inputs.plan_name ]]
       artifacts_access: $[[ inputs.artifacts_access ]]
+      extra_artifacts: $[[ inputs.plan_extra_artifacts ]]
       var_file: $[[ inputs.var_file ]]
       rules: $[[ inputs.plan_rules ]]
       cache_policy: pull
@@ -289,6 +294,7 @@ stages:
           state_name: $[[ inputs.state_name]]
           plan_name: $[[ inputs.plan_name ]]
           artifacts_access: $[[ inputs.artifacts_access ]]
+          plan_extra_artifacts: $[[ inputs.plan_extra_artifacts ]]
           var_file: $[[ inputs.var_file ]]
           fmt_allow_failure: $[[ inputs.fmt_allow_failure ]]
           fmt_rules: $[[ inputs.fmt_rules ]]
diff --git a/tests/iac-upload-artifacts/backend.tf b/tests/iac-upload-artifacts/backend.tf
new file mode 100644
index 0000000000000000000000000000000000000000..1736bf13b6ce62319d00b07243000e4ffea76c3d
--- /dev/null
+++ b/tests/iac-upload-artifacts/backend.tf
@@ -0,0 +1,3 @@
+terraform {
+  backend "http" {}
+}
diff --git a/tests/iac-upload-artifacts/main.tf b/tests/iac-upload-artifacts/main.tf
new file mode 100644
index 0000000000000000000000000000000000000000..6a7ec813a381762f97ea148b8c153faa2c582950
--- /dev/null
+++ b/tests/iac-upload-artifacts/main.tf
@@ -0,0 +1,14 @@
+data "archive_file" "test_artifact" {
+  type        = "zip"
+  output_path = "${path.module}/test-artifact.zip"
+
+  source {
+    content  = "test artifact inner value"
+    filename = "file-inside-archive.txt"
+  }
+}
+
+resource "local_file" "test_copy" {
+  source   = data.archive_file.test_artifact.output_path
+  filename = "${path.module}/test-local-file.zip"
+}
diff --git a/tests/integration-tests/ExtraArtifactsAreIncluded.gitlab-ci.yml b/tests/integration-tests/ExtraArtifactsAreIncluded.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..41617037cee1f5f0b419913c52376600ca82d043
--- /dev/null
+++ b/tests/integration-tests/ExtraArtifactsAreIncluded.gitlab-ci.yml
@@ -0,0 +1,41 @@
+variables:
+  ARTIFACT_FILE_NAME: integration_test_file_artifact
+
+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_GITLAB_TOFU_ROOT_DIR
+      state_name: $TEST_GITLAB_TOFU_STATE_NAME
+      extra_artifacts:
+        - $ARTIFACT_FILE_NAME
+
+  # For CI Terraform state cleanup
+  - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/delete-state@$CI_COMMIT_SHA
+    inputs:
+      state_name: $TEST_GITLAB_TOFU_STATE_NAME
+      rules: [{when: always}]
+
+stages: [build, cleanup, verify]
+
+plan:
+  before_script:
+    - touch "$ARTIFACT_FILE_NAME"
+
+verify:plan-job:uploaded-extra-artifact:
+  stage: verify
+  needs: ['plan']
+  rules: [{when: always}]
+  image: alpine:latest
+  script:
+    - |
+      if [ -f "$ARTIFACT_FILE_NAME" ]; then
+        echo 'Success: the extra artifact was uploaded by the plan job.'
+        exit 0
+      else
+        echo 'Error: the extra artifact was not uploaded by the plan job.'
+        exit 1
+      fi
diff --git a/tests/integration-tests/UploadArtifacts.gitlab-ci.yml b/tests/integration-tests/UploadArtifacts.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8d1005df800dba269bf5d75f3767ea65293638b9
--- /dev/null
+++ b/tests/integration-tests/UploadArtifacts.gitlab-ci.yml
@@ -0,0 +1,24 @@
+include:
+  - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/validate-plan-apply@$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_GITLAB_TOFU_ROOT_DIR
+      state_name: $TEST_GITLAB_TOFU_STATE_NAME
+      fmt_rules: [{when: on_success}]
+      validate_rules: [{when: on_success}]
+      plan_rules: [{when: on_success}]
+      plan_extra_artifacts:
+        - tests/iac-upload-artifacts/
+      apply_rules: [{when: on_success}]
+
+  # For CI Terraform state cleanup
+  - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/delete-state@$CI_COMMIT_SHA
+    inputs:
+      stage: cleanup
+      state_name: $TEST_GITLAB_TOFU_STATE_NAME
+      rules: [{when: always}]
+
+stages: [validate, build, deploy, cleanup]
diff --git a/tests/integration.gitlab-ci.yml b/tests/integration.gitlab-ci.yml
index 6f3be6dec59e66aba46d447e5132ea6a7c0dd80f..1c40ebaf8a8ba1244599ce8f2db1a13234582db0 100644
--- a/tests/integration.gitlab-ci.yml
+++ b/tests/integration.gitlab-ci.yml
@@ -136,6 +136,7 @@ plan-job-template:
     matrix:
       - PIPELINE_NAME:
           - WarningOnNonEmptyPlan
+          - ExtraArtifactsAreIncluded
         GITLAB_OPENTOFU_BASE_IMAGE_OS:
           - alpine
           - debian
@@ -193,3 +194,20 @@ id-tokens:
           - alpine
           - debian
 
+upload-artifacts:
+  stage: test-integration
+  variables:
+    OPENTOFU_VERSION: $LATEST_OPENTOFU_VERSION
+    TEST_GITLAB_TOFU_STATE_NAME: ci-integration-$CI_JOB_NAME_SLUG-$CI_PIPELINE_IID-$CI_NODE_INDEX
+    TEST_GITLAB_TOFU_ROOT_DIR: tests/iac-upload-artifacts
+  trigger:
+    include: tests/integration-tests/$PIPELINE_NAME.gitlab-ci.yml
+    strategy: depend
+  parallel:
+    matrix:
+      - PIPELINE_NAME:
+          - UploadArtifacts
+        GITLAB_OPENTOFU_BASE_IMAGE_OS:
+          - alpine
+          - debian
+