diff --git a/doc/guix.texi b/doc/guix.texi
index 1224104038..d2ba6784de 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -40484,12 +40484,54 @@ Miscellaneous Services
 
 The @code{(gnu services docker)} module provides the following services.
 
+@cindex containerd, container runtime
+@defvar containerd-service-type
+
+This service type operates containerd
+@url{https://containerd.io,containerd}, a daemon responsible for
+overseeing the entire container lifecycle on its host system. This
+includes image handling, storage management, container execution,
+supervision, low-level storage operations, network connections, and
+more.
+
+@end defvar
+
+@deftp {Data Type} containerd-configuration
+This is the data type representing the configuration of containerd.
+
+@table @asis
+
+@item @code{containerd} (default: @code{containerd})
+The containerd daemon package to use.
+
+@item @code{debug?} (default @code{#f})
+Enable or disable debug output.
+
+@item @code{environment-variables} (default: @code{'()})
+List of environment variables to set for @command{containerd}.
+
+This must be a list of strings where each string has the form
+@samp{@var{key}=@var{value}} as in this example:
+
+@lisp
+(list "HTTP_PROXY=socks5://127.0.0.1:9150"
+      "HTTPS_PROXY=socks5://127.0.0.1:9150")
+@end lisp
+
+@end table
+@end deftp
+
 @defvar docker-service-type
 
 This is the type of the service that runs @url{https://www.docker.com,Docker},
 a daemon that can execute application bundles (sometimes referred to as
 ``containers'') in isolated environments.
 
+The @code{containerd-service-type} service need to be added to a system
+configuration, otherwise a message about not any service provides
+@code{containerd} will be displayed during @code{guix system
+reconfigure}.
+
 @end defvar
 
 @deftp {Data Type} docker-configuration
@@ -40504,7 +40546,7 @@ Miscellaneous Services
 The Docker client package to use.
 
 @item @code{containerd} (default: @var{containerd})
-The Containerd package to use.
+This field is deprecated in favor of @code{containerd-service-type} service.
 
 @item @code{proxy} (default @var{docker-libnetwork-cmd-proxy})
 The Docker user-land networking proxy package to use.
diff --git a/gnu/services/docker.scm b/gnu/services/docker.scm
index 7aff8dcc5f..a5375d1ccc 100644
--- a/gnu/services/docker.scm
+++ b/gnu/services/docker.scm
@@ -49,7 +49,9 @@ (define-module (gnu services docker)
   #:use-module (ice-9 format)
   #:use-module (ice-9 match)
 
-  #:export (docker-configuration
+  #:export (containerd-configuration
+            containerd-service-type
+            docker-configuration
             docker-service-type
             singularity-service-type
             oci-image
@@ -95,7 +97,7 @@ (define-configuration docker-configuration
    "Docker client package.")
   (containerd
    (file-like containerd)
-   "containerd package.")
+   "Deprecated.  Do not use.")
   (proxy
    (file-like docker-libnetwork-cmd-proxy)
    "The proxy package to support inter-container and outside-container
@@ -117,6 +119,18 @@ (define-configuration docker-configuration
    "JSON configuration file to pass to dockerd")
   (no-serialization))
 
+(define-configuration containerd-configuration
+  (containerd
+   (file-like containerd)
+   "containerd package.")
+  (debug?
+   (boolean #f)
+   "Enable or disable debug output.")
+  (environment-variables
+   (list '())
+   "Environment variables to set for containerd.")
+  (no-serialization))
+
 (define %docker-accounts
   (list (user-group (name "docker") (system? #t))))
 
@@ -134,24 +148,37 @@ (define (%docker-activation config)
         (mkdir-p #$state-dir))))
 
 (define (containerd-shepherd-service config)
-  (let* ((package (docker-configuration-containerd config))
-         (debug? (docker-configuration-debug? config))
-         (containerd (docker-configuration-containerd config)))
+  (match-record config <containerd-configuration>
+                (containerd debug? environment-variables)
     (shepherd-service
-           (documentation "containerd daemon.")
-           (provision '(containerd))
-           (start #~(make-forkexec-constructor
-                     (list (string-append #$package "/bin/containerd")
-                           #$@(if debug?
-                                  '("--log-level=debug")
-                                  '()))
-                     ;; For finding containerd-shim binary.
-                     #:environment-variables
-                     (list (string-append "PATH=" #$containerd "/bin"))
-                     #:pid-file "/run/containerd/containerd.pid"
-                     #:pid-file-timeout 300
-                     #:log-file "/var/log/containerd.log"))
-           (stop #~(make-kill-destructor)))))
+     (documentation "containerd daemon.")
+     (provision '(containerd))
+     (start #~(make-forkexec-constructor
+               (list (string-append #$containerd "/bin/containerd")
+                     #$@(if debug?
+                            '("--log-level=debug")
+                            '()))
+               ;; For finding containerd-shim binary.
+               #:environment-variables
+               (list #$@environment-variables
+                     (string-append "PATH=" #$containerd "/bin"))
+               #:pid-file "/run/containerd/containerd.pid"
+               #:pid-file-timeout 300
+               #:log-file "/var/log/containerd.log"))
+     (stop #~(make-kill-destructor)))))
+
+(define containerd-service-type
+  (service-type (name 'containerd)
+                (description "Run containerd container runtime.")
+                (extensions
+                 (list
+                  ;; Make sure the 'ctr' command is available.
+                  (service-extension profile-service-type
+                                     (compose list containerd-configuration-containerd))
+                  (service-extension shepherd-root-service-type
+                                     (lambda (config)
+                                       (list (containerd-shepherd-service config))))))
+                (default-value (containerd-configuration))))
 
 (define (docker-shepherd-service config)
   (let* ((docker (docker-configuration-docker config))
@@ -208,8 +235,7 @@ (define docker-service-type
                                      %docker-activation)
                   (service-extension shepherd-root-service-type
                                      (lambda (config)
-                                       (list (containerd-shepherd-service config)
-                                             (docker-shepherd-service config))))
+                                       (list (docker-shepherd-service config))))
                   (service-extension account-service-type
                                      (const %docker-accounts))))
                 (default-value (docker-configuration))))
diff --git a/gnu/tests/docker.scm b/gnu/tests/docker.scm
index d550136b4a..46c886580c 100644
--- a/gnu/tests/docker.scm
+++ b/gnu/tests/docker.scm
@@ -54,6 +54,7 @@ (define %docker-os
    (service dbus-root-service-type)
    (service polkit-service-type)
    (service elogind-service-type)
+   (service containerd-service-type)
    (service docker-service-type)))
 
 (define (run-docker-test docker-tarball)
@@ -88,7 +89,21 @@ (define (run-docker-test docker-tarball)
           (test-runner-current (system-test-runner #$output))
           (test-begin "docker")
 
-          (test-assert "service running"
+          (test-assert "containerd service running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (match (start-service 'containerd)
+                  (#f #f)
+                  (('service response-parts ...)
+                   (match (assq-ref response-parts 'running)
+                     ((pid) (number? pid))))))
+             marionette))
+
+          (test-assert "containerd PID file present"
+            (wait-for-file "/run/containerd/containerd.pid" marionette))
+
+          (test-assert "dockerd service running"
             (marionette-eval
              '(begin
                 (use-modules (gnu services herd))
@@ -234,6 +249,20 @@ (define (run-docker-system-test tarball)
           (test-runner-current (system-test-runner #$output))
           (test-begin "docker")
 
+          (test-assert "containerd service running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (match (start-service 'containerd)
+                  (#f #f)
+                  (('service response-parts ...)
+                   (match (assq-ref response-parts 'running)
+                     ((pid) (number? pid))))))
+             marionette))
+
+          (test-assert "containerd PID file present"
+            (wait-for-file "/run/containerd/containerd.pid" marionette))
+
           (test-assert "service running"
             (marionette-eval
              '(begin
@@ -327,6 +356,7 @@ (define %oci-os
    (service dbus-root-service-type)
    (service polkit-service-type)
    (service elogind-service-type)
+   (service containerd-service-type)
    (service docker-service-type)
    (extra-special-file "/shared.txt"
                        (plain-file "shared.txt" "hello"))
@@ -384,6 +414,20 @@ (define (run-oci-container-test)
           (test-runner-current (system-test-runner #$output))
           (test-begin "oci-container")
 
+          (test-assert "containerd service running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (match (start-service 'containerd)
+                  (#f #f)
+                  (('service response-parts ...)
+                   (match (assq-ref response-parts 'running)
+                     ((pid) (number? pid))))))
+             marionette))
+
+          (test-assert "containerd PID file present"
+            (wait-for-file "/run/containerd/containerd.pid" marionette))
+
           (test-assert "dockerd running"
             (marionette-eval
              '(begin
