diff --git a/docs/glossary.rst b/docs/glossary.rst
index 58484a2..dd3768f 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -227,6 +227,21 @@ Glossary
      :term:`config settings<config setting>`.  See also
      :doc:`narr/config/table`.
 
+   spec
+     As the term is used in Wutta Project context, this refers to a
+     string designating the import path to a particular object (class,
+     function etc.).
+
+     Also the term implies a certain format, namely a dotted module
+     path followed by colon (``:``), then object name.
+
+     For instance, ``wuttjamaican.app:AppHandler`` is the spec string
+     for the :class:`wuttjamaican.app.AppHandler` class (and note, the
+     hyperlink does not use colon, but our "spec" always does).
+
+     See also :meth:`~wuttjamaican.app.AppHandler.load_object()` (on
+     the :term:`app handler`) which can return any object from spec.
+
    subcommand
      A top-level :term:`command` may expose one or more subcommands,
      for the overall command line interface.  Subcommands are usually
diff --git a/src/wuttjamaican/conf.py b/src/wuttjamaican/conf.py
index 785ce7b..2c71e28 100644
--- a/src/wuttjamaican/conf.py
+++ b/src/wuttjamaican/conf.py
@@ -201,7 +201,6 @@ class WuttaConfig:
         self.files_read = []
         for path in files:
             self._load_ini_configs(path, configs, require=True)
-        log.debug("config files were: %s", self.files_read)
 
         # add config for use w/ setdefault()
         self.defaults = configuration.Configuration(defaults)
@@ -249,6 +248,10 @@ class WuttaConfig:
     def _load_ini_configs(self, path, configs, require=True):
         path = os.path.abspath(path)
 
+        # no need to read a file twice; its first appearance sets priority
+        if path in self.files_read:
+            return
+
         # try to load config from the given path
         try:
             config = configuration.config_from_ini(path, read_from_file=True)
diff --git a/tests/test_conf.py b/tests/test_conf.py
index 9ef533e..b5b8771 100644
--- a/tests/test_conf.py
+++ b/tests/test_conf.py
@@ -109,6 +109,39 @@ baz = B
         self.assertIsNone(config.get('foo.bar'))
         self.assertEqual(config.get('foo.baz'), 'B')
 
+    def test_files_only_read_once(self):
+        base = self.write_file('base.conf', """
+[foo]
+bar = 1
+baz = A
+""")
+
+        middle = self.write_file('middle.conf', """
+[wutta.config]
+require = %(here)s/base.conf
+
+[foo]
+baz = B
+""")
+
+        top = self.write_file('top.conf', """
+[wutta.config]
+require = %(here)s/middle.conf
+
+[foo]
+baz = C
+""")
+
+        config = conf.WuttaConfig(files=[top, middle, base])
+        self.assertEqual(len(config.files_read), 3)
+        # nb. files_read listing is in order of "priority" which is
+        # same the as order in which files were initially read
+        self.assertEqual(config.files_read[0], top)
+        self.assertEqual(config.files_read[1], middle)
+        self.assertEqual(config.files_read[2], base)
+        self.assertEqual(config.get('foo.bar'), '1')
+        self.assertEqual(config.get('foo.baz'), 'C')
+
     def test_prioritized_files(self):
         first = self.write_file('first.conf', """\
 [foo]