diff --git a/djaosdb/caosdb_client.py b/djaosdb/caosdb_client.py
index 8291ffd5ee145de0a20b7cce7e47aa2edf28b7cf..021ad7d2fbff2cc7a6c37391d0d149f99998b61a 100644
--- a/djaosdb/caosdb_client.py
+++ b/djaosdb/caosdb_client.py
@@ -121,6 +121,8 @@ class DefaultCaosDBClientDelegate:
             self._caosdb = caosdb
 
         self._caosdb.configure_connection(**kwargs)
+        self._query_cache = {}
+        self._etag = None
 
     def _get_reference_clause(self, type, p, v, negation, sub=None):
         result = (f" REFERENCES {v}"
@@ -162,7 +164,22 @@ class DefaultCaosDBClientDelegate:
             return f' {n}{p}{o}"{v}"'
         raise NotImplementedError("_get_filter_clause(%s)", fil)
 
-    def _query(self, query):
+    def _cache_locally(self, etag, key, value):
+        if etag != self._etag:
+            self._query_cache = {}
+        if key is not None:
+            self._query_cache[key] = value
+
+    def _query(self, query, key=None):
+        if key is not None and key in self.query_local_cache:
+            return self._query_cache[key]
+
+        result = self._query_no_local_cache(query)
+        self._cache_locally(etag, key, result)
+
+        return result
+
+    def _query_no_local_cache(self, query):
         t1 = time.time()
         result = self._caosdb.execute_query(query)
         t2 = time.time()
@@ -176,7 +193,7 @@ class DefaultCaosDBClientDelegate:
             filter_clause = " WITH " + self._get_filter_clause(fil)
 
         query = f'FIND RECORD "{record_type}"{filter_clause}'
-        return self._query(query)
+        return self._query(query, key=query)
 
     def _get_property_values(self, container, projection):
         if projection is None:
@@ -335,10 +352,10 @@ class DefaultCaosDBClientDelegate:
 
     def _aggregate(self, record_type, sort=None, projection=None, limit=None,
                    filter=None, count=False, skip=None):
-        query = self._generate_query(record_type, sort, projection, filter,
+        query, key = self._generate_query(record_type, sort, projection, filter,
                                      count)
 
-        res = self._query(query)
+        res = self._query(query, key=key)
         if count:
             return CountResult(res, count)
         rows = self._get_property_values(res, projection)
@@ -354,7 +371,9 @@ class DefaultCaosDBClientDelegate:
         elif sort is not None:
             prefix = 'SELECT ' + ", ".join(list(projection) +
                                            list(sort.keys())) + " FROM"
-        return f'{prefix} RECORD "{record_type}"{filter_clause}'
+        query = f'{prefix} RECORD "{record_type}"{filter_clause}'
+        key = query if not count else None
+        return query, key
 
     def delete_many(self, record_type, filter):
         container = self._find(record_type, filter=filter)
diff --git a/setup.py b/setup.py
index 78db8ac1e5617f42cb894abbb7bf1e11b54c7914..a8a062f5db108195752e0632f3087f85da6c365e 100644
--- a/setup.py
+++ b/setup.py
@@ -82,7 +82,7 @@ def find_version(*file_paths):
 
 install_requires = [
     'sqlparse==0.2.4',
-    'caosdb>=0.4.0',
+    'caosdb>=0.5.1',
     'django>=2.1',
     'python-dateutil>=2.8.1',
 ]