diff --git a/.circleci/config.yml b/.circleci/config.yml
index 115902f..f9399f7 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -45,7 +45,7 @@ jobs:
             source /tmp/venv/bin/activate
             pip install -U pip
             pip install -r /tmp/src/templateflow/requirements.txt
-            pip install "datalad ~= 0.11.8" doi2bib
+            pip install "datalad ~= 0.11.8" "doi2bib < 0.4"
             pip install "setuptools>=42.0" "setuptools_scm[toml] >= 3.4" twine codecov
 
       - run:
diff --git a/setup.cfg b/setup.cfg
index 16b5cc9..1012368 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -49,7 +49,7 @@ exclude =
 
 [options.extras_require]
 citations =
-    doi2bib
+    doi2bib < 0.4.0
 datalad =
     datalad ~= 0.12.0
 doc =
diff --git a/templateflow/conf/__init__.py b/templateflow/conf/__init__.py
index f4b387b..9d29cf2 100644
--- a/templateflow/conf/__init__.py
+++ b/templateflow/conf/__init__.py
@@ -45,11 +45,19 @@ please set the TEMPLATEFLOW_HOME environment variable.\
 def update(local=False, overwrite=True, silent=False):
     """Update an existing DataLad or S3 home."""
     if TF_USE_DATALAD and _update_datalad():
-        return True
-
-    from ._s3 import update as _update_s3
+        success = True
+    else:
+        from ._s3 import update as _update_s3
+        success = _update_s3(TF_HOME, local=local, overwrite=overwrite, silent=silent)
 
-    return _update_s3(TF_HOME, local=local, overwrite=overwrite, silent=silent)
+    # update Layout only if necessary
+    if success and TF_LAYOUT is not None:
+        init_layout()
+        # ensure the api uses the updated layout
+        import importlib
+        from .. import api
+        importlib.reload(api)
+    return success
 
 
 def setup_home(force=False):
@@ -76,9 +84,12 @@ def _update_datalad():
 
 
 TF_LAYOUT = None
-try:
+
+
+def init_layout():
     from .bids import Layout
 
+    global TF_LAYOUT
     TF_LAYOUT = Layout(
         TF_HOME,
         validate=False,
@@ -92,5 +103,9 @@ try:
             "scripts",
         ],
     )
+
+
+try:
+    init_layout()
 except ImportError:
     pass
diff --git a/templateflow/conf/_s3.py b/templateflow/conf/_s3.py
index 9e20cbe..4051ce8 100644
--- a/templateflow/conf/_s3.py
+++ b/templateflow/conf/_s3.py
@@ -27,7 +27,7 @@ def _get_skeleton_file():
     import requests
 
     try:
-        r = requests.get(TF_SKEL_URL(release="master", ext="md5", allow_redirects=True))
+        r = requests.get(TF_SKEL_URL(release="master", ext="md5"), allow_redirects=True)
     except requests.exceptions.ConnectionError:
         return
 
@@ -35,7 +35,7 @@ def _get_skeleton_file():
         return
 
     if r.content.decode().split()[0] != TF_SKEL_MD5:
-        r = requests.get(TF_SKEL_URL(release="master", ext="zip", allow_redirects=True))
+        r = requests.get(TF_SKEL_URL(release="master", ext="zip"), allow_redirects=True)
         if r.ok:
             from os import close
 

TemplateFlow should re-index the BIDS layout after update
Currently, when `TEMPLATEFLOW_HOME` has been updated in the same python session, the index of the archive remains out-of-date.
diff --git a/templateflow/tests/test_conf.py b/templateflow/tests/test_conf.py
new file mode 100644
index 0000000..c2d95f2
--- /dev/null
+++ b/templateflow/tests/test_conf.py
@@ -0,0 +1,27 @@
+from pathlib import Path
+import pytest
+from .. import conf, api
+
+
+@pytest.mark.skipif(conf.TF_USE_DATALAD, reason="S3 only")
+def test_update_s3(tmp_path):
+    conf.TF_HOME = tmp_path / 'templateflow'
+    conf.TF_HOME.mkdir(exist_ok=True)
+
+    # replace TF_SKEL_URL with the path of a legacy skeleton
+    _skel_url = conf._s3.TF_SKEL_URL
+    conf._s3.TF_SKEL_URL = (
+        "https://github.com/templateflow/python-client/raw/0.5.0/"
+        "templateflow/conf/templateflow-skel.{ext}".format
+    )
+    # initialize templateflow home, making sure to pull the legacy skeleton
+    conf.update(local=False)
+    # ensure we can grab a file
+    assert Path(api.get('MNI152NLin2009cAsym', resolution=2, desc='brain', suffix='mask')).exists()
+    # and ensure we can't fetch one that doesn't yet exist
+    assert not api.get('Fischer344', hemi='L', desc='brain', suffix='mask')
+
+    # refresh the skeleton using the most recent skeleton
+    conf._s3.TF_SKEL_URL = _skel_url
+    conf.update(local=True, overwrite=True)
+    assert Path(api.get('Fischer344', hemi='L', desc='brain', suffix='mask')).exists()

pip install -e .[all]
parse_log_pytest
requirements.txt
pytest
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
appdirs==1.4.4
attrs==25.3.0
babel==2.17.0
backports.tarfile==1.2.0
beautifulsoup4==4.13.3
bids-validator==1.14.7.post0
bidsschematools==1.0.4
bleach==6.2.0
boto==2.49.0
certifi==2025.1.31
cffi==1.17.1
chardet==5.2.0
charset-normalizer==3.4.1
click==8.1.8
colorclass==2.2.2
coverage==7.8.0
cryptography==44.0.2
datalad==0.12.7
defusedxml==0.7.1
Deprecated==1.2.18
distro==1.9.0
docopt==0.6.2
docutils==0.21.2
exceptiongroup==1.2.2
execnet==2.1.1
fasteners==0.19
fastjsonschema==2.21.1
gitdb==4.0.12
GitPython==3.1.44
greenlet==3.1.1
humanize==4.12.2
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
importlib_resources==6.5.2
iniconfig==2.1.0
iso8601==2.1.0
jaraco.classes==3.4.0
jaraco.context==6.0.1
jaraco.functools==4.1.0
jeepney==0.9.0
Jinja2==3.1.6
jsmin==3.0.1
jsonschema==4.23.0
jsonschema-specifications==2024.10.1
jupyter_client==8.6.3
jupyter_core==5.7.2
jupyterlab_pygments==0.3.0
keyring==25.6.0
keyrings.alt==5.0.2
MarkupSafe==3.0.2
mistune==3.1.3
more-itertools==10.6.0
msgpack==1.1.0
nbclient==0.10.2
nbconvert==7.16.6
nbformat==5.10.4
nbsphinx==0.9.7
nibabel==5.3.2
num2words==0.5.14
numpy==2.0.2
packaging==24.2
pandas==2.2.3
pandocfilters==1.5.1
patool==1.15.0
patsy==1.0.1
pbr==6.1.1
platformdirs==4.3.7
pluggy==1.5.0
pockets==0.9.1
pybids==0.11.1
pycparser==2.22
pydot==3.0.4
pydotplus==2.0.2
PyGithub==2.6.1
Pygments==2.19.1
PyJWT==2.10.1
PyNaCl==1.5.0
pyparsing==3.2.3
pytest==8.3.5
pytest-cov==2.5.1
pytest-xdist==3.6.1
python-dateutil==2.9.0.post0
pytz==2025.2
PyYAML==6.0.2
pyzmq==26.3.0
referencing==0.36.2
requests==2.32.3
rpds-py==0.24.0
scipy==1.13.1
SecretStorage==3.3.3
simplejson==3.20.1
six==1.17.0
smmap==5.0.2
snowballstemmer==2.2.0
soupsieve==2.6
Sphinx==7.4.7
sphinx-argparse==0.4.0
sphinx-rtd-theme==3.0.2
sphinxcontrib-apidoc==0.3.0
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-napoleon==0.7
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
sphinxcontrib-versioning==2.2.1
SQLAlchemy==2.0.40
-e git+https://github.com/templateflow/python-client.git@1c473dfa23eac7eed8cefd1ce9fad5ad52331a2e#egg=templateflow
tinycss2==1.4.0
tomli==2.2.1
tornado==6.4.2
tqdm==4.67.1
traitlets==5.14.3
typing_extensions==4.13.0
tzdata==2025.2
urllib3==2.3.0
webencodings==0.5.1
Whoosh==2.7.4
wrapt==1.17.2
zipp==3.21.0

name: python-client
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - appdirs==1.4.4
      - attrs==25.3.0
      - babel==2.17.0
      - backports-tarfile==1.2.0
      - beautifulsoup4==4.13.3
      - bids-validator==1.14.7.post0
      - bidsschematools==1.0.4
      - bleach==6.2.0
      - boto==2.49.0
      - certifi==2025.1.31
      - cffi==1.17.1
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - click==8.1.8
      - colorclass==2.2.2
      - coverage==7.8.0
      - cryptography==44.0.2
      - datalad==0.12.7
      - defusedxml==0.7.1
      - deprecated==1.2.18
      - distro==1.9.0
      - docopt==0.6.2
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - execnet==2.1.1
      - fasteners==0.19
      - fastjsonschema==2.21.1
      - gitdb==4.0.12
      - gitpython==3.1.44
      - greenlet==3.1.1
      - humanize==4.12.2
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - importlib-resources==6.5.2
      - iniconfig==2.1.0
      - iso8601==2.1.0
      - jaraco-classes==3.4.0
      - jaraco-context==6.0.1
      - jaraco-functools==4.1.0
      - jeepney==0.9.0
      - jinja2==3.1.6
      - jsmin==3.0.1
      - jsonschema==4.23.0
      - jsonschema-specifications==2024.10.1
      - jupyter-client==8.6.3
      - jupyter-core==5.7.2
      - jupyterlab-pygments==0.3.0
      - keyring==25.6.0
      - keyrings-alt==5.0.2
      - markupsafe==3.0.2
      - mistune==3.1.3
      - more-itertools==10.6.0
      - msgpack==1.1.0
      - nbclient==0.10.2
      - nbconvert==7.16.6
      - nbformat==5.10.4
      - nbsphinx==0.9.7
      - nibabel==5.3.2
      - num2words==0.5.14
      - numpy==2.0.2
      - packaging==24.2
      - pandas==2.2.3
      - pandocfilters==1.5.1
      - patool==1.15.0
      - patsy==1.0.1
      - pbr==6.1.1
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pockets==0.9.1
      - pybids==0.11.1
      - pycparser==2.22
      - pydot==3.0.4
      - pydotplus==2.0.2
      - pygithub==2.6.1
      - pygments==2.19.1
      - pyjwt==2.10.1
      - pynacl==1.5.0
      - pyparsing==3.2.3
      - pytest==8.3.5
      - pytest-cov==2.5.1
      - pytest-xdist==3.6.1
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyyaml==6.0.2
      - pyzmq==26.3.0
      - referencing==0.36.2
      - requests==2.32.3
      - rpds-py==0.24.0
      - scipy==1.13.1
      - secretstorage==3.3.3
      - simplejson==3.20.1
      - six==1.17.0
      - smmap==5.0.2
      - snowballstemmer==2.2.0
      - soupsieve==2.6
      - sphinx==7.4.7
      - sphinx-argparse==0.4.0
      - sphinx-rtd-theme==3.0.2
      - sphinxcontrib-apidoc==0.3.0
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-napoleon==0.7
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - sphinxcontrib-versioning==2.2.1
      - sqlalchemy==2.0.40
      - templateflow==0.6.4.dev1+g1c473df
      - tinycss2==1.4.0
      - tomli==2.2.1
      - tornado==6.4.2
      - tqdm==4.67.1
      - traitlets==5.14.3
      - typing-extensions==4.13.0
      - tzdata==2025.2
      - urllib3==2.3.0
      - webencodings==0.5.1
      - whoosh==2.7.4
      - wrapt==1.17.2
      - zipp==3.21.0
prefix: /opt/conda/envs/python-client

templateflow/tests/test_conf.py::test_update_s3
templateflow/conf/_s3.py templateflow/conf/__init__.py .circleci/config.yml setup.cfg
templateflow/conf/_s3.py templateflow/conf/__init__.py .circleci/config.yml setup.cfg