diff --git a/.gitlab-ci.common.yml b/.gitlab-ci.common.yml
index 82494622e8305a7bedd95cd7a8292b0d20d823c7..f6bbfd9d71fae3d7fc66e45e78d0e56fcccc5ece 100644
--- a/.gitlab-ci.common.yml
+++ b/.gitlab-ci.common.yml
@@ -11,6 +11,7 @@ workflow:
 # Set to 1 to force a rebuild of the Docker image
 variables:
   BUILD_DOCKER_IMAGE: "0"
+  APPLICATION_LAST_RELEASE: "0.0.0"
 
 stages:
   - versioning
@@ -19,6 +20,7 @@ stages:
   - build
   - test
   - pages
+  - deploy
 
 # This step determines the SHA1 of the Docker file used. It's stored in
 # versions.env artifact. The environment variables are available for all steps
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c5d463511c1815a8828422442a50d36c3637b9fa..4127f8c9cfd2f5cd9c033dd3fd96ecb91f589c1c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -52,6 +52,26 @@ test:
         coverage_format: cobertura
         path: build/coverage.xml
 
+# See https://git.astron.nl/templates/cpp-project/-/wikis/ABI%20checker
+abi-test:
+  stage: test
+  needs: ["versioning", "build-docker-ubuntu-22.04"]
+  image: $BASE_IMAGE
+  script:
+    # The syntax is described at https://docs.gitlab.com/ee/user/packages/generic_packages/index.html
+    - 'curl --header  "JOB-TOKEN: $CI_JOB_TOKEN" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/ABI/${APPLICATION_LAST_RELEASE}/abi.dump" -o abi.dump'
+    - cmake --version
+    - mkdir build && cd build
+    - cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-Og -gdwarf-3" -GNinja ..
+    - ninja
+    - cd ..
+    - abi-dumper build/src/lib/libhello.so -o master.dump -lver master
+    # ABI failures are not only intended to be informative
+    - abi-compliance-checker -l hello -old abi.dump -new master.dump || true
+  artifacts:
+    paths:
+      - compat_reports/hello/${APPLICATION_LAST_RELEASE}_to_master
+
 build:
   stage: build
   needs: ["versioning", "build-docker-ubuntu-22.04"]
@@ -74,3 +94,20 @@ pages:
     # Extract HTML coverage report.
     - tar xfz coverage.tar.gz
     # TODO: Add an index page with links to the documentation and coverage.
+
+abi-deplay:
+  stage: deploy
+  needs: ["versioning", "build-docker-ubuntu-22.04"]
+  image: $BASE_IMAGE
+  environment: production
+  script:
+    - cmake --version
+    - mkdir build && cd build
+    - cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-Og -gdwarf-3" -GNinja ..
+    - ninja
+    - cd ..
+    - abi-dumper build/src/lib/libhello.so -o ${APPLICATION_LAST_RELEASE}.dump -lver ${APPLICATION_LAST_RELEASE}
+    # The syntax is described at https://docs.gitlab.com/ee/user/packages/generic_packages/index.html
+    - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${APPLICATION_LAST_RELEASE}.dump "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/ABI/${APPLICATION_LAST_RELEASE}/abi.dump"'
+  rules:
+    -  when: manual
diff --git a/ci/ubuntu_22_04-base b/ci/ubuntu_22_04-base
index bffc25bd2fae41b1a51e865c7cbdd384fdb43c38..d0e1562ac49444002b5bb8f099745b70d094b490 100644
--- a/ci/ubuntu_22_04-base
+++ b/ci/ubuntu_22_04-base
@@ -7,11 +7,14 @@ FROM ubuntu:22.04
 RUN export DEBIAN_FRONTEND=noninteractive && \
 	apt-get update && \
 	apt-get install -y \
+		abi-compliance-checker \
+		abi-dumper \
 		build-essential \
 		clang-format \
 		clang-tidy \
 		cmake \
 		cmake-format \
+		curl \
 		doxygen \
 		gcovr \
 		git \