diff --git a/hgext/sqlitestore.py b/hgext/sqlitestore.py
--- a/hgext/sqlitestore.py
+++ b/hgext/sqlitestore.py
@@ -288,6 +288,7 @@ class sqliterevisiondelta(object):
     baserevisionsize = attr.ib()
     revision = attr.ib()
     delta = attr.ib()
+    sidedata = attr.ib()
     linknode = attr.ib(default=None)
 
 
@@ -908,6 +909,10 @@ class sqlitefilestore(object):
     def files(self):
         return []
 
+    def sidedata(self, nodeorrev, _df=None):
+        # Not supported for now
+        return {}
+
     def storageinfo(
         self,
         exclusivefiles=False,
diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -618,6 +618,13 @@ def _revisiondeltatochunks(delta, header
         yield prefix
     yield data
 
+    sidedata = delta.sidedata
+    if sidedata is not None:
+        # Need a separate chunk for sidedata to be able to differentiate
+        # "raw delta" length and sidedata length
+        yield chunkheader(len(sidedata))
+        yield sidedata
+
 
 def _sortnodesellipsis(store, nodes, cl, lookup):
     """Sort nodes for changegroup generation."""
diff --git a/mercurial/interfaces/repository.py b/mercurial/interfaces/repository.py
--- a/mercurial/interfaces/repository.py
+++ b/mercurial/interfaces/repository.py
@@ -453,6 +453,10 @@ class irevisiondelta(interfaceutil.Inter
         """
     )
 
+    sidedata = interfaceutil.Attribute(
+        """Raw sidedata bytes for the given revision."""
+    )
+
 
 class ifilerevisionssequence(interfaceutil.Interface):
     """Contains index data for all revisions of a file.
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -204,6 +204,7 @@ class revlogrevisiondelta(object):
     baserevisionsize = attr.ib()
     revision = attr.ib()
     delta = attr.ib()
+    sidedata = attr.ib()
     linknode = attr.ib(default=None)
 
 
@@ -2587,6 +2588,7 @@ class revlog(object):
                     dfh,
                     alwayscache=alwayscache,
                     deltacomputer=deltacomputer,
+                    sidedata=sidedata,
                 )
 
                 if addrevisioncb:
diff --git a/mercurial/testing/storage.py b/mercurial/testing/storage.py
--- a/mercurial/testing/storage.py
+++ b/mercurial/testing/storage.py
@@ -1158,7 +1158,7 @@ class ifilemutationtests(basetestcase):
         f = self._makefilefn()
 
         deltas = [
-            (node0, nullid, nullid, nullid, nullid, delta0, 0),
+            (node0, nullid, nullid, nullid, nullid, delta0, 0, {}),
         ]
 
         with self._maketransactionfn() as tr:
@@ -1214,7 +1214,9 @@ class ifilemutationtests(basetestcase):
         for i, fulltext in enumerate(fulltexts):
             delta = mdiff.trivialdiffheader(len(fulltext)) + fulltext
 
-            deltas.append((nodes[i], nullid, nullid, nullid, nullid, delta, 0))
+            deltas.append(
+                (nodes[i], nullid, nullid, nullid, nullid, delta, 0, {})
+            )
 
         with self._maketransactionfn() as tr:
             newnodes = []
@@ -1262,7 +1264,9 @@ class ifilemutationtests(basetestcase):
             )
 
         delta = mdiff.textdiff(b'bar\n' * 30, (b'bar\n' * 30) + b'baz\n')
-        deltas = [(b'\xcc' * 20, node1, nullid, b'\x01' * 20, node1, delta, 0)]
+        deltas = [
+            (b'\xcc' * 20, node1, nullid, b'\x01' * 20, node1, delta, 0, {})
+        ]
 
         with self._maketransactionfn() as tr:
             with self.assertRaises(error.CensoredBaseError):
diff --git a/mercurial/utils/storageutil.py b/mercurial/utils/storageutil.py
--- a/mercurial/utils/storageutil.py
+++ b/mercurial/utils/storageutil.py
@@ -478,6 +478,7 @@ def emitrevisions(
             baserevisionsize=baserevisionsize,
             revision=revision,
             delta=delta,
+            sidedata=sidedata,
         )
 
         prevrev = rev