diff --git a/nomad/app/dcat/mapping.py b/nomad/app/dcat/mapping.py
index 035be01de2ffec66f203f73f2f06dbec84b2e473..de33cc947315f652bf2426c850699733b6164fb5 100644
--- a/nomad/app/dcat/mapping.py
+++ b/nomad/app/dcat/mapping.py
@@ -24,6 +24,7 @@ from .api import url
 
 
 VCARD = Namespace('http://www.w3.org/2006/vcard/ns#')
+HYDRA = Namespace('http://www.w3.org/ns/hydra/core#')
 
 
 def get_optional_entry_prop(entry, name):
@@ -40,26 +41,46 @@ class Mapping():
         self.g.namespace_manager.bind('dct', DCT)
         self.g.namespace_manager.bind('vcard', VCARD)
         self.g.namespace_manager.bind('foaf', FOAF)
+        self.g.namespace_manager.bind('hydra', HYDRA)
 
         self.persons = {}
 
     def map_catalog(self, entries):
         catalog = URIRef(url('catalog'))
         self.g.add((catalog, RDF.type, DCAT.Catalog))
+        last_entry = None
         for entry in entries:
-            self.g.add((catalog, DCT.dataset, self.map_entry(entry)))
-
-    def map_entry(self, entry: EntryMetadata):
+            self.g.add((catalog, DCT.dataset, self.map_entry(entry, slim=True)))
+            last_entry = entry
+
+        hydra_collection = BNode()
+        self.g.add((hydra_collection, RDF.type, HYDRA.Collection))
+        self.g.add((hydra_collection, HYDRA.totalItems, Literal(entries.total)))
+        self.g.add((
+            hydra_collection, HYDRA.first,
+            URIRef('%s/catalog' % config.api_url(api='dcat'), last_entry.calc_id)))
+        if last_entry is not None:
+            next_url = '%s/catalog?after=%s' % (config.api_url(api='dcat'), last_entry.calc_id)
+            self.g.add((hydra_collection, HYDRA.next, URIRef(next_url)))
+
+        self.g.add((catalog, HYDRA.collection, hydra_collection))
+
+    def map_entry(self, entry: EntryMetadata, slim=False):
         dataset = URIRef(url('datasets', entry.calc_id))
 
         self.g.add((dataset, RDF.type, DCAT.Dataset))
         self.g.add((dataset, DCT.identifier, Literal(entry.calc_id)))
         self.g.add((dataset, DCT.issued, Literal(entry.upload_time)))
         self.g.add((dataset, DCT.modified, Literal(entry.last_processing)))
-        self.g.add((dataset, DCAT.landing_page, URIRef('%s/entry/id/%s/%s' % (
-            config.gui_url(), entry.upload_id, entry.calc_id))))
         self.g.add((dataset, DCT.title, Literal(get_optional_entry_prop(entry, 'formula'))))
         self.g.add((dataset, DCT.description, Literal(get_optional_entry_prop(entry, 'comment'))))
+
+        if slim:
+            return dataset
+
+        self.g.add((dataset, DCAT.landing_page, URIRef('%s/entry/id/%s/%s' % (
+            config.gui_url(), entry.upload_id, entry.calc_id))))
+
         self.g.add((dataset, DCT.license, URIRef('https://creativecommons.org/licenses/by/4.0/legalcode')))
         self.g.add((dataset, DCT.language, URIRef('http://id.loc.gov/vocabulary/iso639-1/en')))
 
diff --git a/nomad/config.py b/nomad/config.py
index d25ff5f3165d3be595c0f25810c181ac57a5d1f6..3226bd9bd9f333695675d47393d1c593f1816f8e 100644
--- a/nomad/config.py
+++ b/nomad/config.py
@@ -173,12 +173,14 @@ tests = NomadConfig(
 )
 
 
-def api_url(ssl: bool = True):
-    return '%s://%s/%s/api' % (
+def api_url(ssl: bool = True, api: str = 'api'):
+    base_url = '%s://%s/%s' % (
         'https' if services.https and ssl else 'http',
         services.api_host.strip('/'),
         services.api_base_path.strip('/'))
 
+    return '%s/%s' % (base_url.strip('/'), api)
+
 
 def gui_url(page: str = None):
     base = api_url(True)[:-3]