diff --git a/apptainer-build-ci.yml b/apptainer-build-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9e82c764eb06d7529ba8bcc0157322f5ab2327ec
--- /dev/null
+++ b/apptainer-build-ci.yml
@@ -0,0 +1,39 @@
+stages:
+  - build
+  - push
+
+Build:
+    tags:
+    - apptainer
+    - build
+    stage: build
+    script:
+      - apptainer build ${CI_PROJECT_NAME}.sif container.def
+
+# Tag the "main" branch as "latest"
+Push latest:
+  variables:
+    # We do not need GitLab to clone the source code.
+    GIT_STRATEGY: none
+  stage: push
+  tags:
+    - apptainer
+    - build
+  # Only "main" should be tagged "latest"
+  rules:
+    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+  script:
+    - apptainer push ${CI_PROJECT_NAME}.sif oras://container-registry.surrey.ac.uk/shared-containers/${CI_PROJECT_NAME}:latest
+
+Push branch:
+  variables:
+    # We do not need GitLab to clone the source code.
+    GIT_STRATEGY: none
+  stage: push
+  tags:
+    - apptainer
+    - build
+  rules:
+    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
+  script:
+    - apptainer push ${CI_PROJECT_NAME}.sif oras://container-registry.surrey.ac.uk/shared-containers/${CI_PROJECT_NAME}:SHA_$CI_COMMIT_SHORT_SHA