diff --git a/modules/services/nextcloud-server.nix b/modules/services/nextcloud-server.nix
index b194ba0..f881616 100644
--- a/modules/services/nextcloud-server.nix
+++ b/modules/services/nextcloud-server.nix
@@ -277,6 +277,50 @@ in
             };
           };
 
+          externalStorage = lib.mkOption {
+            # TODO: would be nice to have quota include external storage but it's not supported for root:
+            # https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/user_configuration.html#setting-storage-quotas
+            description = ''
+              External Storage App. [Manual](https://docs.nextcloud.com/server/28/go.php?to=admin-external-storage)
+
+              Set `userLocalMount` to automatically add a local directory as an external storage.
+              Use this option if you want to store user data in another folder or another hard drive
+              altogether.
+
+              In the `directory` option, you can use either `$user` and/or `$home` which will be
+              replaced by the user's name and home directory.
+
+              Recommended use of this option is to have the Nextcloud's `dataDir` on a SSD and the
+              `userLocalRooDirectory` on a HDD. Indeed, a SSD is much quicker than a spinning hard
+              drive, which is well suited for randomly accessing small files like thumbnails. On the
+              other side, a spinning hard drive can store more data which is well suited for storing
+              user data.
+            '';
+            default = {};
+            type = lib.types.submodule {
+              options = {
+                enable = lib.mkEnableOption "Nextcloud External Storage App";
+                userLocalMount = lib.mkOption {
+                  default = null;
+                  type = lib.types.nullOr (lib.types.submodule {
+                    options = {
+                      directory = lib.mkOption {
+                        type = lib.types.str;
+                        example = "/srv/nextcloud";
+                      };
+
+                      mountName = lib.mkOption {
+                        type = lib.types.str;
+                        default = "";
+                        example = "local";
+                      };
+                    };
+                  });
+                };
+              };
+            };
+          };
+
           ldap = lib.mkOption {
             description = ''
               LDAP Integration App. [Manual](https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/user_auth_ldap.html)
@@ -718,6 +762,28 @@ in
       };
     })
 
+    (lib.mkIf cfg.apps.externalStorage.enable {
+      systemd.services.nextcloud-setup.script = ''
+        ${occ} app:install files_external || :
+        ${occ} app:enable  files_external
+      '' + lib.optionalString (cfg.apps.externalStorage.userLocalMount != "") (
+        let
+          cfg' = cfg.apps.externalStorage.userLocalMount;
+
+          escape = x: builtins.replaceStrings ["/"] [''\\\/''] x;
+        in
+          ''
+          ${occ} files_external:list \
+                   | grep '${escape cfg'.mountName}' \
+                   | grep '${escape cfg'.directory}' \
+          || ${occ} files_external:create \
+                   '${cfg'.mountName}' \
+                   local \
+                   null::null \
+                   --config datadir='${cfg'.directory}'
+          '');
+    })
+
     (lib.mkIf cfg.apps.ldap.enable {
       systemd.services.nextcloud-setup.path = [ pkgs.jq ];
       systemd.services.nextcloud-setup.script = ''
diff --git a/modules/services/nextcloud-server/docs/default.md b/modules/services/nextcloud-server/docs/default.md
index d89e2f1..80bccb1 100644
--- a/modules/services/nextcloud-server/docs/default.md
+++ b/modules/services/nextcloud-server/docs/default.md
@@ -12,6 +12,8 @@ This NixOS module is a service that sets up a [Nextcloud Server](https://nextclo
   - [OIDC](#services-nextcloud-server-usage-oidc) app: enables app and sets up integration with an existing OIDC server.
   - [Preview Generator](#services-nextcloud-server-usage-previewgenerator) app: enables app and sets
     up required cron job.
+  - [External Storage](#services-nextcloud-server-usage-externalstorage) app: enables app and
+    optionally configures one local mount.
   - [Only Office](#services-nextcloud-server-usage-onlyoffice) app: enables app and sets up Only
     Office service.
   - Any other app through the
@@ -302,6 +304,35 @@ You can opt-out with:
 shb.nextcloud.apps.previewgenerator.recommendedSettings = false;
 ```
 
+### Enable External Storage App {#services-nextcloud-server-usage-externalstorage}
+
+The following snippet installs and enables the [External
+Storage](https://docs.nextcloud.com/server/28/go.php?to=admin-external-storage) application.
+
+```nix
+shb.nextcloud.apps.externalStorage.enable = true;
+```
+
+Optionally creates a local mount point with:
+
+```nix
+externalStorage = {
+  userLocalMount.rootDirectory = "/srv/nextcloud/$user";
+  userLocalMount.mountName = "home";
+};
+```
+
+You can even make the external storage be at the root with:
+
+```nix
+externalStorage.userLocalMount.mountName = "/";
+```
+
+Recommended use of this app is to have the Nextcloud's `dataDir` on a SSD and the
+`userLocalRooDirectory` on a HDD. Indeed, a SSD is much quicker than a spinning hard drive, which is
+well suited for randomly accessing small files like thumbnails. On the other side, a spinning hard
+drive can store more data which is well suited for storing user data.
+
 ### Enable OnlyOffice App {#services-nextcloud-server-usage-onlyoffice}
 
 The following snippet installs and enables the [Only