diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
index 2b279126b8f50ae269558b89e742aa127ef638cf_bWVyY3VyaWFsL2xvY2FscmVwby5weQ==..4c0a5a256ae806fab18d56b3c44a8d1c98a40ce0_bWVyY3VyaWFsL2xvY2FscmVwby5weQ== 100644
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -284,6 +284,12 @@
         else:
             self.supported = self._basesupported
 
+        # Add compression engines.
+        for name in util.compengines:
+            engine = util.compengines[name]
+            if engine.revlogheader():
+                self.supported.add('exp-compression-%s' % name)
+
         if not self.vfs.isdir():
             if create:
                 self.requirements = newreporequirements(self)
@@ -397,6 +403,10 @@
         self.svfs.options['aggressivemergedeltas'] = aggressivemergedeltas
         self.svfs.options['lazydeltabase'] = not scmutil.gddeltaconfig(self.ui)
 
+        for r in self.requirements:
+            if r.startswith('exp-compression-'):
+                self.svfs.options['compengine'] = r[len('exp-compression-'):]
+
     def _writerequirements(self):
         scmutil.writerequires(self.vfs, self.requirements)
 
@@ -1994,6 +2004,18 @@
             if ui.configbool('format', 'dotencode', True):
                 requirements.add('dotencode')
 
+    compengine = ui.config('experimental', 'format.compression', 'zlib')
+    if compengine not in util.compengines:
+        raise error.Abort(_('compression engine %s defined by '
+                            'experimental.format.compression not available') %
+                          compengine,
+                          hint=_('run "hg debuginstall" to list available '
+                                 'compression engines'))
+
+    # zlib is the historical default and doesn't need an explicit requirement.
+    if compengine != 'zlib':
+        requirements.add('exp-compression-%s' % compengine)
+
     if scmutil.gdinitconfig(ui):
         requirements.add('generaldelta')
     if ui.configbool('experimental', 'treemanifest', False):
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
index 2b279126b8f50ae269558b89e742aa127ef638cf_bWVyY3VyaWFsL3JldmxvZy5weQ==..4c0a5a256ae806fab18d56b3c44a8d1c98a40ce0_bWVyY3VyaWFsL3JldmxvZy5weQ== 100644
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -272,6 +272,7 @@
         # Mapping of revision integer to full node.
         self._nodecache = {nullid: nullrev}
         self._nodepos = None
+        self._compengine = 'zlib'
 
         v = REVLOG_DEFAULT_VERSION
         opts = getattr(opener, 'options', None)
@@ -288,6 +289,8 @@
             if 'aggressivemergedeltas' in opts:
                 self._aggressivemergedeltas = opts['aggressivemergedeltas']
             self._lazydeltabase = bool(opts.get('lazydeltabase', False))
+            if 'compengine' in opts:
+                self._compengine = opts['compengine']
 
         if self._chunkcachesize <= 0:
             raise RevlogError(_('revlog chunk cache size %r is not greater '
@@ -345,7 +348,7 @@
 
     @util.propertycache
     def _compressor(self):
-        return util.compengines['zlib'].revlogcompressor()
+        return util.compengines[self._compengine].revlogcompressor()
 
     def tip(self):
         return self.node(len(self.index) - 2)
diff --git a/tests/test-repo-compengines.t b/tests/test-repo-compengines.t
new file mode 100644
index 0000000000000000000000000000000000000000..4c0a5a256ae806fab18d56b3c44a8d1c98a40ce0_dGVzdHMvdGVzdC1yZXBvLWNvbXBlbmdpbmVzLnQ=
--- /dev/null
+++ b/tests/test-repo-compengines.t
@@ -0,0 +1,78 @@
+A new repository uses zlib storage, which doesn't need a requirement
+
+  $ hg init default
+  $ cd default
+  $ cat .hg/requires
+  dotencode
+  fncache
+  generaldelta
+  revlogv1
+  store
+
+  $ touch foo
+  $ hg -q commit -A -m 'initial commit with a lot of repeated repeated repeated text to trigger compression'
+  $ hg debugrevlog -c | grep 0x78
+      0x78 (x)  :   1 (100.00%)
+      0x78 (x)  : 110 (100.00%)
+
+  $ cd ..
+
+Unknown compression engine to format.compression aborts
+
+  $ hg --config experimental.format.compression=unknown init unknown
+  abort: compression engine unknown defined by experimental.format.compression not available
+  (run "hg debuginstall" to list available compression engines)
+  [255]
+
+A requirement specifying an unknown compression engine results in bail
+
+  $ hg init unknownrequirement
+  $ cd unknownrequirement
+  $ echo exp-compression-unknown >> .hg/requires
+  $ hg log
+  abort: repository requires features unknown to this Mercurial: exp-compression-unknown!
+  (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
+  [255]
+
+  $ cd ..
+
+#if zstd
+
+  $ hg --config experimental.format.compression=zstd init zstd
+  $ cd zstd
+  $ cat .hg/requires
+  dotencode
+  exp-compression-zstd
+  fncache
+  generaldelta
+  revlogv1
+  store
+
+  $ touch foo
+  $ hg -q commit -A -m 'initial commit with a lot of repeated repeated repeated text'
+
+  $ hg debugrevlog -c | grep 0x28
+      0x28      :  1 (100.00%)
+      0x28      : 98 (100.00%)
+
+  $ cd ..
+
+Specifying a new format.compression on an existing repo won't introduce data
+with that engine or a requirement
+
+  $ cd default
+  $ touch bar
+  $ hg --config experimental.format.compression=zstd -q commit -A -m 'add bar with a lot of repeated repeated repeated text'
+
+  $ cat .hg/requires
+  dotencode
+  fncache
+  generaldelta
+  revlogv1
+  store
+
+  $ hg debugrevlog -c | grep 0x78
+      0x78 (x)  :   2 (100.00%)
+      0x78 (x)  : 199 (100.00%)
+
+#endif