diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 123c11ac28737e79ef645058ca6b773f6827243f..0cc4dabc4521544b65fb56a788c02018a60da80e 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,6 +2,18 @@ This document contains the ``fslpy`` release history in reverse chronological
 order.
 
 
+2.6.0 (Under development)
+-------------------------
+
+
+Changed
+^^^^^^^
+
+
+* The :class:`.Cache` class has a new ``lru`` option, allowing it to be used
+  as a least-recently-used cache.
+
+
 2.5.0 (Tuesday 6th August 2019)
 -------------------------------
 
diff --git a/fsl/utils/cache.py b/fsl/utils/cache.py
index 5a89817d99520d83b3a8d3729b9dd117e0cb0be9..cf50a50aa281f1d8ad8b27e06160ecfe16598085 100644
--- a/fsl/utils/cache.py
+++ b/fsl/utils/cache.py
@@ -42,14 +42,20 @@ class Cache(object):
          raised.
     """
 
-    def __init__(self, maxsize=100):
+    def __init__(self, maxsize=100, lru=False):
         """Create a ``Cache``.
 
         :arg maxsize: Maximum number of items allowed in the ``Cache`` before
                       it starts dropping old items
+
+        :arg lru:     (least recently used) If ``False`` (the default), items
+                      are dropped according to their insertion time. Otherwise,
+                      items are dropped according to their most recent access
+                      time.
         """
         self.__cache   = collections.OrderedDict()
         self.__maxsize = maxsize
+        self.__lru     = lru
 
 
     def put(self, key, value, expiry=0):
@@ -94,14 +100,26 @@ class Cache(object):
         else:
             entry = self.__cache[key]
 
+        # Check to see if the entry
+        # has expired
+        now = time.time()
+
         if entry.expiry > 0:
-            if time.time() - entry.storetime > entry.expiry:
+            if now - entry.storetime > entry.expiry:
 
                 self.__cache.pop(key)
 
                 if defaultSpecified: return default
                 else:                raise Expired(key)
 
+        # If we are an lru cache, update
+        # this entry's expiry, and update
+        # its order in the cache dict
+        if self.__lru:
+            entry.storetime = now
+            self.__cache.pop(key)
+            self.__cache[key] = entry
+
         return entry.value
 
 
@@ -125,6 +143,13 @@ class Cache(object):
         return self.put(key, value)
 
 
+    def __contains__(self, key):
+        """Check whether an item is in the cache. Note that the item may
+        be in the cache, but it may be expired.
+        """
+        return key in self.__cache
+
+
     def __parseDefault(self, *args, **kwargs):
         """Used by the :meth:`get` method. Parses the ``default`` argument,
         which may be specified as either a positional or keyword argumnet.
@@ -134,7 +159,7 @@ class Cache(object):
                     - ``True`` if a default argument was specified, ``False``
                       otherwise.
 
-                    - The specifeid default value, or ``None`` if it wasn't
+                    - The specified default value, or ``None`` if it wasn't
                       specified.
         """
 
diff --git a/tests/test_cache.py b/tests/test_cache.py
index cb643ae43291043e9fa643358c6acac289c1af86..4dcc970323d2b2e2e2c81a5a05ededb796918516 100644
--- a/tests/test_cache.py
+++ b/tests/test_cache.py
@@ -113,7 +113,36 @@ def test_expiry():
     with pytest.raises(cache.Expired):
         c.get(0)
 
+    with pytest.raises(cache.Expired):
+        c.get(1)
+
     assert c.get(1, default='default') == 'default'
 
     # And that the cache is empty
     assert len(c) == 0
+
+
+def test_lru():
+    c = cache.Cache(maxsize=3, lru=True)
+
+    c[0] = '0'
+    c[1] = '1'
+    c[2] = '2'
+    c[3] = '3'
+
+    # normal behaviour - first inserted
+    # is dropped
+    with pytest.raises(KeyError):
+        assert c.get(0)
+
+    # lru behaviour - oldest accessed is
+    # dropped
+    c[1]
+    c[4] = '4'
+    with pytest.raises(KeyError):
+        c[2]
+
+    c[1]
+    c[3]
+    c[4]
+    assert len(c) == 3