diff --git a/model_server/base/accessors.py b/model_server/base/accessors.py
index b250605d4df5de6b1cd18d3a2570a85ed532f319..43d400f9587253b4e2fd2fc62a59ceb1acd39857 100644
--- a/model_server/base/accessors.py
+++ b/model_server/base/accessors.py
@@ -24,6 +24,10 @@ class GenericImageDataAccessor(ABC):
         """
         pass
 
+    @property
+    def loaded(self):
+        return self._data is not None
+
     @property
     def chroma(self):
         return self.shape_dict['C']
@@ -38,6 +42,7 @@ class GenericImageDataAccessor(ABC):
     def is_3d(self):
         return True if self.shape_dict['Z'] > 1 else False
 
+    # TODO: no direct calls to self._data outside load/unload methods
     def is_mask(self):
         return is_mask(self._data)
 
@@ -198,7 +203,7 @@ class InMemoryDataAccessor(GenericImageDataAccessor):
         self._data = self.conform_data(data)
 
 class GenericImageFileAccessor(GenericImageDataAccessor): # image data is loaded from a file
-    def __init__(self, fpath: Path):
+    def __init__(self, fpath: Path, lazy=False):
         """
         Interface for image data that originates in an image file
         :param fpath: absolute path to image file
@@ -208,6 +213,15 @@ class GenericImageFileAccessor(GenericImageDataAccessor): # image data is loaded
             raise FileAccessorError(f'Could not find file at {fpath}')
         self.fpath = fpath
 
+        if not lazy:
+            self._data = self.load()
+        else:
+            self._data = None
+
+    @abstractmethod
+    def load(self):
+        pass
+
     @staticmethod
     def read(fp: Path):
         return generate_file_accessor(fp)
@@ -219,12 +233,12 @@ class GenericImageFileAccessor(GenericImageDataAccessor): # image data is loaded
         return d
 
 class TifSingleSeriesFileAccessor(GenericImageFileAccessor):
-    def __init__(self, fpath: Path):
-        super().__init__(fpath)
+    def load(self):
+        fpath = self.fpath
 
         try:
             tf = tifffile.TiffFile(fpath)
-            self.tf = tf
+            self.tf = tf # TODO: close file connection
         except Exception:
             raise FileAccessorError(f'Unable to access data in {fpath}')
 
@@ -251,14 +265,15 @@ class TifSingleSeriesFileAccessor(GenericImageFileAccessor):
             [0, 1, 2, 3]
         )
 
-        self._data = self.conform_data(yxcz.reshape(yxcz.shape[0:4]))
+        return self.conform_data(yxcz.reshape(yxcz.shape[0:4]))
 
+    # TODO: remove
     def __del__(self):
         self.tf.close()
 
 class PngFileAccessor(GenericImageFileAccessor):
-    def __init__(self, fpath: Path):
-        super().__init__(fpath)
+    def load(self):
+        fpath = self.fpath
 
         try:
             arr = imread(fpath)
@@ -266,19 +281,19 @@ class PngFileAccessor(GenericImageFileAccessor):
             FileAccessorError(f'Unable to access data in {fpath}')
 
         if len(arr.shape) == 3: # rgb
-            self._data = np.expand_dims(arr, 3)
+            return np.expand_dims(arr, 3)
         else: # mono
-            self._data = np.expand_dims(arr, (2, 3))
+            return np.expand_dims(arr, (2, 3))
 
 class CziImageFileAccessor(GenericImageFileAccessor):
     """
-    Image that is stored in a Zeiss .CZI file; may be multi-channel, and/or a z-stack,
-    but not a time series or multiposition acquisition.
+    Image that is stored in a Zeiss .CZI file; may be multi-channel, and/or a z-stack, but not a time series
+    or multiposition acquisition.  Read the whole file as a single accessor, no interaction with subblocks.
     """
-    def __init__(self, fpath: Path):
-        super().__init__(fpath)
-
+    def load(self):
+        fpath = self.fpath
         try:
+            # TODO: persist metadata then remove file connection
             cf = czifile.CziFile(fpath)
             self.czifile = cf
         except Exception:
@@ -302,7 +317,7 @@ class CziImageFileAccessor(GenericImageFileAccessor):
             [cf.axes.index(ch) for ch in idx],
             [0, 1, 2, 3]
         )
-        self._data = self.conform_data(yxcz.reshape(yxcz.shape[0:4]))
+        return self.conform_data(yxcz.reshape(yxcz.shape[0:4]))
 
     def __del__(self):
         self.czifile.close()
@@ -363,21 +378,21 @@ def write_accessor_data_to_file(fpath: Path, acc: GenericImageDataAccessor, mkdi
     return True
 
 
-def generate_file_accessor(fpath):
+def generate_file_accessor(fpath, **kwargs):
     """
     Given an image file path, return an image accessor, assuming the file is a supported format and represents
     a single position array, which may be single or multichannel, single plane or z-stack.
     """
     if str(fpath).upper().endswith('.TIF') or str(fpath).upper().endswith('.TIFF'):
-        return TifSingleSeriesFileAccessor(fpath)
+        return TifSingleSeriesFileAccessor(fpath, **kwargs)
     elif str(fpath).upper().endswith('.CZI'):
-        return CziImageFileAccessor(fpath)
+        return CziImageFileAccessor(fpath, **kwargs)
     elif str(fpath).upper().endswith('.PNG'):
-        return PngFileAccessor(fpath)
+        return PngFileAccessor(fpath, **kwargs)
     else:
         raise FileAccessorError(f'Could not match a file accessor with {fpath}')
 
-
+# TODO: implement lazy loading at patch stack level
 class PatchStack(InMemoryDataAccessor):
 
     axes = 'PYXCZ'
diff --git a/model_server/base/session.py b/model_server/base/session.py
index 1dfd8f3078d9adba0f103e776821f3691d2adb47..5f8c6611e7cd476a4d4a83cc53289d6b94744635 100644
--- a/model_server/base/session.py
+++ b/model_server/base/session.py
@@ -163,10 +163,11 @@ class _Session(object):
         if accessor_id is None:
             idx = len(self.accessors)
             accessor_id = f'acc_{idx:06d}'
-        self.accessors[accessor_id] = {'loaded': True, 'object': acc, **acc.info}
+        self.accessors[accessor_id] = {'loaded': acc.loaded, 'object': acc, **acc.info}
         self.log_info(f'Added accessor {accessor_id}')
         return accessor_id
 
+    # TODO: divergent cases between lazy file-backed accessor (with its own loaded state) and in-memory ones
     def del_accessor(self, accessor_id: str) -> str:
         """
         Remove accessor object but retain its info dictionary
diff --git a/tests/base/test_accessors.py b/tests/base/test_accessors.py
index e73e347029f5ec42cd01696ebdf01a0ae4c0cff0..f17053988cb814d83b047036f37762d33328255d 100644
--- a/tests/base/test_accessors.py
+++ b/tests/base/test_accessors.py
@@ -228,6 +228,9 @@ class TestCziImageFileAccess(unittest.TestCase):
             )
         )
 
+    def test_lazy_load(self):
+        cf = generate_file_accessor(data['czifile']['path'])
+        self.assertEqual(1, 0)
 
 class TestPatchStackAccessor(unittest.TestCase):
     def setUp(self) -> None: