diff --git a/packages/HighFive/.gitrepo b/packages/HighFive/.gitrepo
index 7d436d3458ed5f6d35f34ecd46f1c0975d9a2352..98988c87ecab65e9d9e9215ea6684fa53407fd3b 100644
--- a/packages/HighFive/.gitrepo
+++ b/packages/HighFive/.gitrepo
@@ -6,7 +6,7 @@
 [subrepo]
 	remote = git@github.com:BlueBrain/HighFive.git
 	branch = master
-	commit = 1299c556a992bea8aa03c3b75cca50560a5078b6
+	commit = d04789128123e1a643c6284e28087be1dafae2ee
 	parent = ce26d02b1f92356362dc4daede0babf8d4ac23b6
 	method = merge
 	cmdver = 0.4.6
diff --git a/packages/HighFive/CHANGELOG.md b/packages/HighFive/CHANGELOG.md
index 9a8cd86139f80bc1523e6f0e33fc049316a0f830..fcd0247e37b370f52587440147d5bc4aa2cf541d 100644
--- a/packages/HighFive/CHANGELOG.md
+++ b/packages/HighFive/CHANGELOG.md
@@ -1,4 +1,24 @@
 # Changes
+## Version 2.9.0 - 2024-01-25
+### New Features
+    - Add named ctors for scalar and null dataspaces. (#899)
+    - Named ctor for empty property lists. (#904)
+
+### Improvements
+    - Enable running tests in parallel. (#849)
+    - Wrap all used HDF5 function calls and always check status codes. (#863)
+    - Utilities for writing tests in a container independent manner. (#871)
+    - Improve test rigour.
+
+### Bug Fix
+    - Log messages were slightly misformatted. (#854)
+    - Fix bug in `enforce_ascii_hack`. (#856)
+    - Fix `create_datatype<bool>()`. (#869)
+    - Guard functionality introduced in 1.10.0. (#905)
+    - `inspector` guard for empty containers. (#913)
+    - Avoid non-collective behaviour. (#912)
+
+
 ## Version 2.8.0 - 2023-11-02
 ### Important Change
     - `Eigen::Matrix` is (by default) stored with column-major index ordering. Under
diff --git a/packages/HighFive/CMakeLists.txt b/packages/HighFive/CMakeLists.txt
index d592f2d66db1e448fbdf94cb24237070a120ee3a..694960090842b6a8c27676a336fe4a40e1266b39 100644
--- a/packages/HighFive/CMakeLists.txt
+++ b/packages/HighFive/CMakeLists.txt
@@ -5,7 +5,7 @@ else()
   cmake_policy(VERSION 3.13)
 endif()
 
-project(HighFive VERSION 2.8.0)
+project(HighFive VERSION 2.9.0)
 
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/highfive/H5Version.hpp.in
                ${CMAKE_CURRENT_SOURCE_DIR}/include/highfive/H5Version.hpp)
diff --git a/packages/HighFive/README.md b/packages/HighFive/README.md
index 3ea0680157cdc72040a39c68c2f4ebe2d1569ca1..bc0d2752ed71792b5bfa95116efc7822d3812d66 100644
--- a/packages/HighFive/README.md
+++ b/packages/HighFive/README.md
@@ -1,6 +1,6 @@
 # HighFive - HDF5 header-only C++ Library
 
-[![Doxygen -> gh-pages](https://github.com/BlueBrain/HighFive/workflows/gh-pages/badge.svg)](https://BlueBrain.github.io/HighFive)
+[![Doxygen -> gh-pages](https://github.com/BlueBrain/HighFive/workflows/gh-pages/badge.svg?branch=master)](https://BlueBrain.github.io/HighFive/actions/workflows/gh-pages.yml?query=branch%3Amaster)
 [![codecov](https://codecov.io/gh/BlueBrain/HighFive/branch/master/graph/badge.svg?token=UBKxHEn7RS)](https://codecov.io/gh/BlueBrain/HighFive)
 [![HighFive_Integration_tests](https://github.com/BlueBrain/HighFive-testing/actions/workflows/integration.yml/badge.svg)](https://github.com/BlueBrain/HighFive-testing/actions/workflows/integration.yml)
 
@@ -82,7 +82,8 @@ std::string filename = "/tmp/new_file.h5";
 }
 ```
 
-**Note:** `H5File.hpp` is the top-level header of HighFive core which should be always included.
+**Note:** As of 2.8.0, one can use `highfive/highfive.hpp` to include
+everything HighFive. Prior to 2.8.0 one would include `highfive/H5File.hpp`.
 
 **Note:** For advanced usecases the dataset can be created without immediately
 writing to it. This is common in MPI-IO related patterns, or when growing a
diff --git a/packages/HighFive/doc/Doxyfile b/packages/HighFive/doc/Doxyfile
index 6ebc393ec29919bda054ca1ebf962c23a1f1ceff..d0cf7efb1bc607ad1adbd6628ead1e5a9653a793 100644
--- a/packages/HighFive/doc/Doxyfile
+++ b/packages/HighFive/doc/Doxyfile
@@ -866,6 +866,7 @@ WARN_LOGFILE           =
 
 INPUT                  = @CMAKE_CURRENT_SOURCE_DIR@/../include \
                          @CMAKE_CURRENT_SOURCE_DIR@/installation.md \
+                         @CMAKE_CURRENT_SOURCE_DIR@/migration_guide.md \
                          @CMAKE_CURRENT_SOURCE_DIR@/developer_guide.md \
                          @CMAKE_CURRENT_SOURCE_DIR@/../CHANGELOG.md \
                          @CMAKE_CURRENT_SOURCE_DIR@/../README.md
diff --git a/packages/HighFive/doc/migration_guide.md b/packages/HighFive/doc/migration_guide.md
new file mode 100644
index 0000000000000000000000000000000000000000..e85002b150c5c002a9d896736946c0260429cc58
--- /dev/null
+++ b/packages/HighFive/doc/migration_guide.md
@@ -0,0 +1,16 @@
+# Migration Guide
+A collection of tips for migrating away from deprecated features.
+
+## Deprecation of `FixedLenStringArray`.
+The issue with `FixedLenStringArray` is that it is unable to avoid copies.
+Essentially, this class acts as a means to create a copy of the data in a
+format suitable for writing fixed-length strings. Additionally, the class acts
+as a tag for HighFive to overload on. The support of `std::string` in HighFive
+has improved considerable. Since 2.8.0 we can write/read `std::string` to fixed
+or variable length HDF5 strings.
+
+Therefore, this class serves no purpose anymore. Any occurrence of it can be
+replaced with an `std::vector<std::string>` (for example).
+
+If desired one can silence warnings by replacing `FixedLenStringArray` with
+`deprecated::FixedLenStringArray`.
diff --git a/packages/HighFive/include/highfive/H5DataType.hpp b/packages/HighFive/include/highfive/H5DataType.hpp
index 0d596965fea83fe2a97820be62249254c140af5d..b15f62165afcf5adc4254d79dc41acbb9889404c 100644
--- a/packages/HighFive/include/highfive/H5DataType.hpp
+++ b/packages/HighFive/include/highfive/H5DataType.hpp
@@ -342,6 +342,7 @@ template <typename T>
 DataType create_and_check_datatype();
 
 
+namespace deprecated {
 ///
 /// \brief A structure representing a set of fixed-length strings
 ///
@@ -460,6 +461,11 @@ class FixedLenStringArray {
   private:
     vector_t datavec;
 };
+}  // namespace deprecated
+
+template <size_t N>
+using FixedLenStringArray H5_DEPRECATED_USING("Use 'std::vector<std::string>'.") =
+    deprecated::FixedLenStringArray<N>;
 
 }  // namespace HighFive
 
diff --git a/packages/HighFive/include/highfive/H5Version.hpp b/packages/HighFive/include/highfive/H5Version.hpp
index dc238432cb01d651769c663276ea15a94008f3e9..bca2c3a83066e9e666840473c355c5ade91f1b87 100644
--- a/packages/HighFive/include/highfive/H5Version.hpp
+++ b/packages/HighFive/include/highfive/H5Version.hpp
@@ -9,7 +9,7 @@
 #pragma once
 
 #define HIGHFIVE_VERSION_MAJOR 2
-#define HIGHFIVE_VERSION_MINOR 8
+#define HIGHFIVE_VERSION_MINOR 9
 #define HIGHFIVE_VERSION_PATCH 0
 
 /** \brief Concatenated representation of the HighFive version.
@@ -24,10 +24,10 @@
  *  std::cout << STRINGIFY_VALUE(HIGHFIVE_VERSION) << "\n";
  *  \endcode
  */
-#define HIGHFIVE_VERSION 2.8.0
+#define HIGHFIVE_VERSION 2.9.0
 
 /** \brief String representation of the HighFive version.
  *
  *  \warning This macro only exists from 2.7.1 onwards.
  */
-#define HIGHFIVE_VERSION_STRING "2.8.0"
+#define HIGHFIVE_VERSION_STRING "2.9.0"
diff --git a/packages/HighFive/include/highfive/bits/H5Attribute_misc.hpp b/packages/HighFive/include/highfive/bits/H5Attribute_misc.hpp
index 33295d40e55a0e8c1ac111699114eafaf4fd0b9c..cc235b50074f90f948e8b4b22678e1ee44091274 100644
--- a/packages/HighFive/include/highfive/bits/H5Attribute_misc.hpp
+++ b/packages/HighFive/include/highfive/bits/H5Attribute_misc.hpp
@@ -64,7 +64,7 @@ inline void Attribute::read(T& array) const {
     const details::BufferInfo<T> buffer_info(
         file_datatype,
         [this]() -> std::string { return this->getName(); },
-        details::BufferInfo<T>::read);
+        details::BufferInfo<T>::Operation::read);
 
     if (!details::checkDimensions(mem_space, buffer_info.n_dimensions)) {
         std::ostringstream ss;
@@ -130,7 +130,7 @@ inline void Attribute::write(const T& buffer) {
     const details::BufferInfo<T> buffer_info(
         file_datatype,
         [this]() -> std::string { return this->getName(); },
-        details::BufferInfo<T>::write);
+        details::BufferInfo<T>::Operation::write);
 
     if (!details::checkDimensions(mem_space, buffer_info.n_dimensions)) {
         std::ostringstream ss;
diff --git a/packages/HighFive/include/highfive/bits/H5DataType_misc.hpp b/packages/HighFive/include/highfive/bits/H5DataType_misc.hpp
index e29c99b0ed30c8baf555e685ed5a6dc746c9fa6c..619e51e7189e47db7649100c63c1ef82837b8536 100644
--- a/packages/HighFive/include/highfive/bits/H5DataType_misc.hpp
+++ b/packages/HighFive/include/highfive/bits/H5DataType_misc.hpp
@@ -207,7 +207,7 @@ class AtomicType<char[StrLen]>: public DataType {
 };
 
 template <size_t StrLen>
-class AtomicType<FixedLenStringArray<StrLen>>: public DataType {
+class AtomicType<deprecated::FixedLenStringArray<StrLen>>: public DataType {
   public:
     inline AtomicType()
         : DataType(create_string(StrLen)) {}
@@ -239,8 +239,7 @@ AtomicType<T>::AtomicType() {
 }
 
 
-// class FixedLenStringArray<N>
-
+namespace deprecated {
 template <std::size_t N>
 inline FixedLenStringArray<N>::FixedLenStringArray(const char array[][N], std::size_t length) {
     datavec.resize(length);
@@ -283,6 +282,7 @@ template <std::size_t N>
 inline std::string FixedLenStringArray<N>::getString(std::size_t i) const {
     return std::string(datavec[i].data());
 }
+}  // namespace deprecated
 
 // Internal
 // Reference mapping
diff --git a/packages/HighFive/include/highfive/bits/H5Inspector_misc.hpp b/packages/HighFive/include/highfive/bits/H5Inspector_misc.hpp
index 1613f87c3392df4e4c37d706a0eb211c31e86ed6..7ae90d84f167e3757b5246787971929cbb6a73bd 100644
--- a/packages/HighFive/include/highfive/bits/H5Inspector_misc.hpp
+++ b/packages/HighFive/include/highfive/bits/H5Inspector_misc.hpp
@@ -289,10 +289,10 @@ struct inspector<Reference>: type_helper<Reference> {
 };
 
 template <size_t N>
-struct inspector<FixedLenStringArray<N>> {
-    using type = FixedLenStringArray<N>;
+struct inspector<deprecated::FixedLenStringArray<N>> {
+    using type = deprecated::FixedLenStringArray<N>;
     using value_type = char*;
-    using base_type = FixedLenStringArray<N>;
+    using base_type = deprecated::FixedLenStringArray<N>;
     using hdf5_type = char;
 
     static constexpr size_t ndim = 1;
@@ -591,6 +591,21 @@ struct inspector<T[N]> {
     static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
                                                   inspector<value_type>::is_trivially_copyable;
 
+    static void prepare(type& val, const std::vector<size_t>& dims) {
+        if (dims.size() < 1) {
+            throw DataSpaceException("Invalid 'dims', must be at least 1 dimensional.");
+        }
+
+        if (dims[0] != N) {
+            throw DataSpaceException("Dimensions mismatch.");
+        }
+
+        std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
+        for (size_t i = 0; i < dims[0]; ++i) {
+            inspector<value_type>::prepare(val[i], next_dims);
+        }
+    }
+
     static size_t getSizeVal(const type& val) {
         return compute_total_size(getDimensions(val));
     }
@@ -608,6 +623,10 @@ struct inspector<T[N]> {
         return inspector<value_type>::data(val[0]);
     }
 
+    static hdf5_type* data(type& val) {
+        return inspector<value_type>::data(val[0]);
+    }
+
     /* it works because there is only T[][][] currently
        we will fix it one day */
     static void serialize(const type& val, hdf5_type* m) {
diff --git a/packages/HighFive/include/highfive/bits/H5Node_traits.hpp b/packages/HighFive/include/highfive/bits/H5Node_traits.hpp
index 493749beecd0e94203028d071eaffabd44f6f8c0..6f4a93ce6a963d6d3d4fb9e1f1c65fa57380dc12 100644
--- a/packages/HighFive/include/highfive/bits/H5Node_traits.hpp
+++ b/packages/HighFive/include/highfive/bits/H5Node_traits.hpp
@@ -53,20 +53,7 @@ class NodeTraits {
     /// \param accessProps A property list with data set access properties
     /// \param parents Create intermediate groups if needed. Default: true.
     /// \return DataSet Object
-    template <typename T,
-              typename std::enable_if<
-                  std::is_same<typename details::inspector<T>::base_type, details::Boolean>::value,
-                  int>::type* = nullptr>
-    DataSet createDataSet(const std::string& dataset_name,
-                          const DataSpace& space,
-                          const DataSetCreateProps& createProps = DataSetCreateProps::Default(),
-                          const DataSetAccessProps& accessProps = DataSetAccessProps::Default(),
-                          bool parents = true);
-
-    template <typename T,
-              typename std::enable_if<
-                  !std::is_same<typename details::inspector<T>::base_type, details::Boolean>::value,
-                  int>::type* = nullptr>
+    template <typename T>
     DataSet createDataSet(const std::string& dataset_name,
                           const DataSpace& space,
                           const DataSetCreateProps& createProps = DataSetCreateProps::Default(),
@@ -92,8 +79,9 @@ class NodeTraits {
 
 
     template <std::size_t N>
+    H5_DEPRECATED("Use 'std::vector<std::string>'.")
     DataSet createDataSet(const std::string& dataset_name,
-                          const FixedLenStringArray<N>& data,
+                          const deprecated::FixedLenStringArray<N>& data,
                           const DataSetCreateProps& createProps = DataSetCreateProps::Default(),
                           const DataSetAccessProps& accessProps = DataSetAccessProps::Default(),
                           bool parents = true);
diff --git a/packages/HighFive/include/highfive/bits/H5Node_traits_misc.hpp b/packages/HighFive/include/highfive/bits/H5Node_traits_misc.hpp
index b09bc3190d1136d1385748fa2546c9b1e40a2064..a98600598ad7647598633378456230706ff99a5a 100644
--- a/packages/HighFive/include/highfive/bits/H5Node_traits_misc.hpp
+++ b/packages/HighFive/include/highfive/bits/H5Node_traits_misc.hpp
@@ -52,28 +52,7 @@ inline DataSet NodeTraits<Derivate>::createDataSet(const std::string& dataset_na
 }
 
 template <typename Derivate>
-template <typename T,
-          typename std::enable_if<
-              std::is_same<typename details::inspector<T>::base_type, details::Boolean>::value,
-              int>::type*>
-inline DataSet NodeTraits<Derivate>::createDataSet(const std::string& dataset_name,
-                                                   const DataSpace& space,
-                                                   const DataSetCreateProps& createProps,
-                                                   const DataSetAccessProps& accessProps,
-                                                   bool parents) {
-    return createDataSet(dataset_name,
-                         space,
-                         create_and_check_datatype<typename details::inspector<T>::base_type>(),
-                         createProps,
-                         accessProps,
-                         parents);
-}
-
-template <typename Derivate>
-template <typename T,
-          typename std::enable_if<
-              !std::is_same<typename details::inspector<T>::base_type, details::Boolean>::value,
-              int>::type*>
+template <typename T>
 inline DataSet NodeTraits<Derivate>::createDataSet(const std::string& dataset_name,
                                                    const DataSpace& space,
                                                    const DataSetCreateProps& createProps,
@@ -104,7 +83,7 @@ inline DataSet NodeTraits<Derivate>::createDataSet(const std::string& dataset_na
 template <typename Derivate>
 template <std::size_t N>
 inline DataSet NodeTraits<Derivate>::createDataSet(const std::string& dataset_name,
-                                                   const FixedLenStringArray<N>& data,
+                                                   const deprecated::FixedLenStringArray<N>& data,
                                                    const DataSetCreateProps& createProps,
                                                    const DataSetAccessProps& accessProps,
                                                    bool parents) {
diff --git a/packages/HighFive/include/highfive/bits/H5ReadWrite_misc.hpp b/packages/HighFive/include/highfive/bits/H5ReadWrite_misc.hpp
index 4f6f1578851cc2d72b2584e3737559b8be83aa4b..05bb49888cf8d75b14c8fbf41fe27dd067cd0dd8 100644
--- a/packages/HighFive/include/highfive/bits/H5ReadWrite_misc.hpp
+++ b/packages/HighFive/include/highfive/bits/H5ReadWrite_misc.hpp
@@ -51,7 +51,7 @@ struct BufferInfo {
     using char_array_t = typename details::type_char_array<type_no_const>::type;
     static constexpr bool is_char_array = details::type_char_array<type_no_const>::is_char_array;
 
-    enum Operation { read, write };
+    enum class Operation { read, write };
     const Operation op;
 
     template <class F>
@@ -131,29 +131,29 @@ struct string_type_checker<char*> {
 
 template <typename T>
 template <class F>
-BufferInfo<T>::BufferInfo(const DataType& dtype, F getName, Operation _op)
+BufferInfo<T>::BufferInfo(const DataType& file_data_type, F getName, Operation _op)
     : op(_op)
-    , is_fixed_len_string(dtype.isFixedLenStr())
+    , is_fixed_len_string(file_data_type.isFixedLenStr())
     // In case we are using Fixed-len strings we need to subtract one dimension
     , n_dimensions(details::inspector<type_no_const>::recursive_ndim -
                    ((is_fixed_len_string && is_char_array) ? 1 : 0))
-    , data_type(
-          string_type_checker<char_array_t>::getDataType(create_datatype<elem_type>(), dtype)) {
+    , data_type(string_type_checker<char_array_t>::getDataType(create_datatype<elem_type>(),
+                                                               file_data_type)) {
     // We warn. In case they are really not convertible an exception will rise on read/write
-    if (dtype.getClass() != data_type.getClass()) {
+    if (file_data_type.getClass() != data_type.getClass()) {
         HIGHFIVE_LOG_WARN(getName() + "\": data and hdf5 dataset have different types: " +
-                          data_type.string() + " -> " + dtype.string());
-    } else if ((dtype.getClass() & data_type.getClass()) == DataTypeClass::Float) {
+                          data_type.string() + " -> " + file_data_type.string());
+    } else if ((file_data_type.getClass() & data_type.getClass()) == DataTypeClass::Float) {
         HIGHFIVE_LOG_WARN_IF(
-            (op == read) && (dtype.getSize() > data_type.getSize()),
+            (op == Operation::read) && (file_data_type.getSize() > data_type.getSize()),
             getName() + "\": hdf5 dataset has higher floating point precision than data on read: " +
-                dtype.string() + " -> " + data_type.string());
+                file_data_type.string() + " -> " + data_type.string());
 
         HIGHFIVE_LOG_WARN_IF(
-            (op == write) && (dtype.getSize() < data_type.getSize()),
+            (op == Operation::write) && (file_data_type.getSize() < data_type.getSize()),
             getName() +
                 "\": data has higher floating point precision than hdf5 dataset on write: " +
-                data_type.string() + " -> " + dtype.string());
+                data_type.string() + " -> " + file_data_type.string());
     }
 }
 
diff --git a/packages/HighFive/include/highfive/bits/H5Utils.hpp b/packages/HighFive/include/highfive/bits/H5Utils.hpp
index 2d9d24f887174e5719949c7f4a2bb03b52829a94..b3f039e20d29377269a12cfe6126df7bb3027ed6 100644
--- a/packages/HighFive/include/highfive/bits/H5Utils.hpp
+++ b/packages/HighFive/include/highfive/bits/H5Utils.hpp
@@ -25,9 +25,11 @@
 
 namespace HighFive {
 
+namespace deprecated {
 // If ever used, recognize dimensions of FixedLenStringArray
 template <std::size_t N>
 class FixedLenStringArray;
+}  // namespace deprecated
 
 namespace details {
 // converter function for hsize_t -> size_t when hsize_t != size_t
diff --git a/packages/HighFive/include/highfive/bits/H5_definitions.hpp b/packages/HighFive/include/highfive/bits/H5_definitions.hpp
index 746723c8839344ef8cc2dcc55a9170029ce13f47..ad4b95af2a9af52f92e14196eff5247c848ab96e 100644
--- a/packages/HighFive/include/highfive/bits/H5_definitions.hpp
+++ b/packages/HighFive/include/highfive/bits/H5_definitions.hpp
@@ -5,10 +5,17 @@
 #elif defined(_MSC_VER)
 #define H5_DEPRECATED(msg) __declspec(deprecated(#msg))
 #else
-#pragma message("WARNING: Compiler doesnt support deprecation")
+#pragma message("WARNING: Compiler doesn't support deprecation")
 #define H5_DEPRECATED(msg)
 #endif
 
+#if defined(__GNUC__) || defined(__clang__)
+#define H5_DEPRECATED_USING(msg) H5_DEPRECATED((msg))
+#else
+#pragma message("WARNING: Compiler doesn't support deprecating using statements.")
+#define H5_DEPRECATED_USING(msg)
+#endif
+
 
 // Forward declarations
 
@@ -38,8 +45,10 @@ class AtomicType;
 template <typename Derivate>
 class AnnotateTraits;
 
+namespace deprecated {
 template <std::size_t N>
 class FixedLenStringArray;
+}
 
 template <typename Derivate>
 class NodeTraits;
diff --git a/packages/HighFive/src/examples/read_write_fixedlen_string.cpp b/packages/HighFive/src/examples/read_write_fixedlen_string.cpp
deleted file mode 100644
index 60589637ea97e6c526ab8b8c6754026c7191331d..0000000000000000000000000000000000000000
--- a/packages/HighFive/src/examples/read_write_fixedlen_string.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *  Copyright (c), 2020, Blue Brain Project
- *
- *  Distributed under the Boost Software License, Version 1.0.
- *    (See accompanying file LICENSE_1_0.txt or copy at
- *          http://www.boost.org/LICENSE_1_0.txt)
- *
- */
-#include <iostream>
-#include <string>
-
-#include <highfive/highfive.hpp>
-
-using namespace HighFive;
-
-// This examples shows how compile time constant strings work.
-//
-// Note, that as of version 2.8.0., writing `std::string` as fixed-length
-// strings there's a simpler API.
-int main() {
-    // Create a new file using the default property lists.
-    File file("create_dataset_string_example.h5", File::Truncate);
-    const char strings_fixed[][16] = {"abcabcabcabcabc", "123123123123123"};
-
-    // create a dataset ready to contains strings of the size of the vector
-    file.createDataSet<char[10]>("ds1", DataSpace(2)).write(strings_fixed);
-
-    // Without specific type info this will create an int8 dataset
-    file.createDataSet("ds2", strings_fixed);
-
-    // Now test the new interface type
-    FixedLenStringArray<10> arr{"0000000", "1111111"};
-    auto ds = file.createDataSet("ds3", arr);
-
-    // Read back truncating to 4 chars
-    FixedLenStringArray<4> array_back;
-    ds.read(array_back);
-    std::cout << "First item is '" << array_back[0] << "'\n"
-              << "Second item is '" << array_back[1] << "'\n";
-
-    return 0;
-}
diff --git a/packages/HighFive/tests/unit/CMakeLists.txt b/packages/HighFive/tests/unit/CMakeLists.txt
index b8943067f7bc3055aa871b808ab8cae8d16782f5..2f01bdd81473cbc46e8ca990127e85b1c6d7eb34 100644
--- a/packages/HighFive/tests/unit/CMakeLists.txt
+++ b/packages/HighFive/tests/unit/CMakeLists.txt
@@ -52,3 +52,5 @@ if(HIGHFIVE_TEST_SINGLE_INCLUDES)
         target_link_libraries("tests_include_${CLASS_NAME}" HighFive HighFiveWarnings)
     endforeach()
 endif()
+
+add_subdirectory(deprecated)
diff --git a/packages/HighFive/tests/unit/deprecated/CMakeLists.txt b/packages/HighFive/tests/unit/deprecated/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5e515374bfe5c67779613a6d8e165153ccebb735
--- /dev/null
+++ b/packages/HighFive/tests/unit/deprecated/CMakeLists.txt
@@ -0,0 +1,10 @@
+foreach(test_name test_fixed_len_string_array)
+  add_executable(${test_name} "${test_name}.cpp")
+
+  target_link_libraries(${test_name} HighFive HighFiveWarnings Catch2::Catch2WithMain)
+  catch_discover_tests(${test_name})
+
+  if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+    target_compile_options(${test_name} PRIVATE -Wno-deprecated-declarations)
+  endif()
+endforeach()
diff --git a/packages/HighFive/tests/unit/deprecated/test_fixed_len_string_array.cpp b/packages/HighFive/tests/unit/deprecated/test_fixed_len_string_array.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1d0c33aaa243134c3e99c3c2d769cc3b3902bb4c
--- /dev/null
+++ b/packages/HighFive/tests/unit/deprecated/test_fixed_len_string_array.cpp
@@ -0,0 +1,172 @@
+#include <catch2/catch_test_macros.hpp>
+
+#include <highfive/highfive.hpp>
+#include "../tests_high_five.hpp"
+
+namespace HighFive {
+
+TEST_CASE("HighFiveFixedLenStringArray") {
+    const std::string file_name("fixed_len_string_array.h5");
+
+    // Create a new file using the default property lists.
+    File file(file_name, File::ReadWrite | File::Create | File::Truncate);
+
+    {  // Dedicated FixedLenStringArray (now deprecated).
+        FixedLenStringArray<10> arr{"0000000", "1111111"};
+
+        // More API: test inserting something
+        arr.push_back("2222");
+        auto ds = file.createDataSet("ds7", arr);  // Short syntax ok
+
+        // Recover truncating
+        FixedLenStringArray<4> array_back;
+        ds.read(array_back);
+        CHECK(array_back.size() == 3);
+        CHECK(array_back[0] == std::string("000"));
+        CHECK(array_back[1] == std::string("111"));
+        CHECK(array_back[2] == std::string("222"));
+        CHECK(array_back.getString(1) == "111");
+        CHECK(array_back.front() == std::string("000"));
+        CHECK(array_back.back() == std::string("222"));
+        CHECK(array_back.data() == std::string("000"));
+        array_back.data()[0] = 'x';
+        CHECK(array_back.data() == std::string("x00"));
+
+        for (auto& raw_elem: array_back) {
+            raw_elem[1] = 'y';
+        }
+        CHECK(array_back.getString(1) == "1y1");
+        for (auto iter = array_back.cbegin(); iter != array_back.cend(); ++iter) {
+            CHECK((*iter)[1] == 'y');
+        }
+    }
+}
+
+template <size_t N>
+static void check_fixed_len_string_array_contents(const FixedLenStringArray<N>& array,
+                                                  const std::vector<std::string>& expected) {
+    REQUIRE(array.size() == expected.size());
+
+    for (size_t i = 0; i < array.size(); ++i) {
+        CHECK(array[i] == expected[i]);
+    }
+}
+
+
+TEST_CASE("HighFiveFixedLenStringArrayStructure") {
+    using fixed_array_t = FixedLenStringArray<10>;
+    // increment the characters of a string written in a std::array
+    auto increment_string = [](const fixed_array_t::value_type arr) {
+        fixed_array_t::value_type output(arr);
+        for (auto& c: output) {
+            if (c == 0) {
+                break;
+            }
+            ++c;
+        }
+        return output;
+    };
+
+    SECTION("create from std::vector (onpoint)") {
+        auto expected = std::vector<std::string>{"000", "111"};
+        auto actual = FixedLenStringArray<4>(expected);
+        check_fixed_len_string_array_contents(actual, expected);
+    }
+
+    SECTION("create from std::vector (oversized)") {
+        auto expected = std::vector<std::string>{"000", "111"};
+        auto actual = FixedLenStringArray<8>(expected);
+        check_fixed_len_string_array_contents(actual, expected);
+    }
+
+    SECTION("create from pointers (onpoint)") {
+        auto expected = std::vector<std::string>{"000", "111"};
+        auto actual = FixedLenStringArray<4>(expected.data(), expected.data() + expected.size());
+        check_fixed_len_string_array_contents(actual, expected);
+    }
+
+    SECTION("create from pointers (oversized)") {
+        auto expected = std::vector<std::string>{"000", "111"};
+        auto actual = FixedLenStringArray<8>(expected.data(), expected.data() + expected.size());
+        check_fixed_len_string_array_contents(actual, expected);
+    }
+
+
+    SECTION("create from std::initializer_list (onpoint)") {
+        auto expected = std::vector<std::string>{"000", "111"};
+        auto actual = FixedLenStringArray<4>{"000", "111"};
+        check_fixed_len_string_array_contents(actual, expected);
+    }
+
+    SECTION("create from std::initializer_list (oversized)") {
+        auto expected = std::vector<std::string>{"000", "111"};
+        auto actual = FixedLenStringArray<8>{"000", "111"};
+        check_fixed_len_string_array_contents(actual, expected);
+    }
+
+    // manipulate FixedLenStringArray with std::copy
+    SECTION("compatible with std::copy") {
+        const fixed_array_t arr1{"0000000", "1111111"};
+        fixed_array_t arr2{"0000000", "1111111"};
+        std::copy(arr1.begin(), arr1.end(), std::back_inserter(arr2));
+        CHECK(arr2.size() == 4);
+    }
+
+    SECTION("compatible with std::transform") {
+        fixed_array_t arr;
+        {
+            const fixed_array_t arr1{"0000000", "1111111"};
+            std::transform(arr1.begin(), arr1.end(), std::back_inserter(arr), increment_string);
+        }
+        CHECK(arr.size() == 2);
+        CHECK(arr[0] == std::string("1111111"));
+        CHECK(arr[1] == std::string("2222222"));
+    }
+
+    SECTION("compatible with std::transform (reverse iterator)") {
+        fixed_array_t arr;
+        {
+            const fixed_array_t arr1{"0000000", "1111111"};
+            std::copy(arr1.rbegin(), arr1.rend(), std::back_inserter(arr));
+        }
+        CHECK(arr.size() == 2);
+        CHECK(arr[0] == std::string("1111111"));
+        CHECK(arr[1] == std::string("0000000"));
+    }
+
+    SECTION("compatible with std::remove_copy_if") {
+        fixed_array_t arr2;
+        {
+            const fixed_array_t arr1{"0000000", "1111111"};
+            std::remove_copy_if(arr1.begin(),
+                                arr1.end(),
+                                std::back_inserter(arr2),
+                                [](const fixed_array_t::value_type& s) {
+                                    return std::strncmp(s.data(), "1111111", 7) == 0;
+                                });
+        }
+        CHECK(arr2.size() == 1);
+        CHECK(arr2[0] == std::string("0000000"));
+    }
+}
+
+TEST_CASE("HighFiveFixedLenStringArrayAttribute") {
+    const std::string file_name("fixed_array_attr.h5");
+    // Create a new file using the default property lists.
+    {
+        File file(file_name, File::ReadWrite | File::Create | File::Truncate);
+        FixedLenStringArray<10> arr{"Hello", "world"};
+        file.createAttribute("str", arr);
+    }
+    // Re-read it
+    {
+        File file(file_name);
+        FixedLenStringArray<8> arr;  // notice the output strings can be smaller
+        file.getAttribute("str").read(arr);
+        CHECK(arr.size() == 2);
+        CHECK(arr[0] == std::string("Hello"));
+        CHECK(arr[1] == std::string("world"));
+    }
+}
+
+}  // namespace HighFive
diff --git a/packages/HighFive/tests/unit/tests_high_five_base.cpp b/packages/HighFive/tests/unit/tests_high_five_base.cpp
index 163535b55cdd0875ac7203dfabf39e1ce1f29c69..fefdcdd5586fa3748a99a729b2103e3232ba5739 100644
--- a/packages/HighFive/tests/unit/tests_high_five_base.cpp
+++ b/packages/HighFive/tests/unit/tests_high_five_base.cpp
@@ -2405,36 +2405,6 @@ TEST_CASE("HighFiveFixedString") {
         file.createDataSet<char[10]>("ds6", DataSpace(1)).write(buffer);
     }
 
-    {  // Dedicated FixedLenStringArray
-        FixedLenStringArray<10> arr{"0000000", "1111111"};
-
-        // More API: test inserting something
-        arr.push_back("2222");
-        auto ds = file.createDataSet("ds7", arr);  // Short syntax ok
-
-        // Recover truncating
-        FixedLenStringArray<4> array_back;
-        ds.read(array_back);
-        CHECK(array_back.size() == 3);
-        CHECK(array_back[0] == std::string("000"));
-        CHECK(array_back[1] == std::string("111"));
-        CHECK(array_back[2] == std::string("222"));
-        CHECK(array_back.getString(1) == "111");
-        CHECK(array_back.front() == std::string("000"));
-        CHECK(array_back.back() == std::string("222"));
-        CHECK(array_back.data() == std::string("000"));
-        array_back.data()[0] = 'x';
-        CHECK(array_back.data() == std::string("x00"));
-
-        for (auto& raw_elem: array_back) {
-            raw_elem[1] = 'y';
-        }
-        CHECK(array_back.getString(1) == "1y1");
-        for (auto iter = array_back.cbegin(); iter != array_back.cend(); ++iter) {
-            CHECK((*iter)[1] == 'y');
-        }
-    }
-
     {
         // Direct way of writing `std::string` as a fixed length
         // HDF5 string.
@@ -2492,132 +2462,6 @@ TEST_CASE("HighFiveFixedString") {
     }
 }
 
-template <size_t N>
-static void check_fixed_len_string_array_contents(const FixedLenStringArray<N>& array,
-                                                  const std::vector<std::string>& expected) {
-    REQUIRE(array.size() == expected.size());
-
-    for (size_t i = 0; i < array.size(); ++i) {
-        CHECK(array[i] == expected[i]);
-    }
-}
-
-TEST_CASE("HighFiveFixedLenStringArrayStructure") {
-    using fixed_array_t = FixedLenStringArray<10>;
-    // increment the characters of a string written in a std::array
-    auto increment_string = [](const fixed_array_t::value_type arr) {
-        fixed_array_t::value_type output(arr);
-        for (auto& c: output) {
-            if (c == 0) {
-                break;
-            }
-            ++c;
-        }
-        return output;
-    };
-
-    SECTION("create from std::vector (onpoint)") {
-        auto expected = std::vector<std::string>{"000", "111"};
-        auto actual = FixedLenStringArray<4>(expected);
-        check_fixed_len_string_array_contents(actual, expected);
-    }
-
-    SECTION("create from std::vector (oversized)") {
-        auto expected = std::vector<std::string>{"000", "111"};
-        auto actual = FixedLenStringArray<8>(expected);
-        check_fixed_len_string_array_contents(actual, expected);
-    }
-
-    SECTION("create from pointers (onpoint)") {
-        auto expected = std::vector<std::string>{"000", "111"};
-        auto actual = FixedLenStringArray<4>(expected.data(), expected.data() + expected.size());
-        check_fixed_len_string_array_contents(actual, expected);
-    }
-
-    SECTION("create from pointers (oversized)") {
-        auto expected = std::vector<std::string>{"000", "111"};
-        auto actual = FixedLenStringArray<8>(expected.data(), expected.data() + expected.size());
-        check_fixed_len_string_array_contents(actual, expected);
-    }
-
-
-    SECTION("create from std::initializer_list (onpoint)") {
-        auto expected = std::vector<std::string>{"000", "111"};
-        auto actual = FixedLenStringArray<4>{"000", "111"};
-        check_fixed_len_string_array_contents(actual, expected);
-    }
-
-    SECTION("create from std::initializer_list (oversized)") {
-        auto expected = std::vector<std::string>{"000", "111"};
-        auto actual = FixedLenStringArray<8>{"000", "111"};
-        check_fixed_len_string_array_contents(actual, expected);
-    }
-
-    // manipulate FixedLenStringArray with std::copy
-    SECTION("compatible with std::copy") {
-        const fixed_array_t arr1{"0000000", "1111111"};
-        fixed_array_t arr2{"0000000", "1111111"};
-        std::copy(arr1.begin(), arr1.end(), std::back_inserter(arr2));
-        CHECK(arr2.size() == 4);
-    }
-
-    SECTION("compatible with std::transform") {
-        fixed_array_t arr;
-        {
-            const fixed_array_t arr1{"0000000", "1111111"};
-            std::transform(arr1.begin(), arr1.end(), std::back_inserter(arr), increment_string);
-        }
-        CHECK(arr.size() == 2);
-        CHECK(arr[0] == std::string("1111111"));
-        CHECK(arr[1] == std::string("2222222"));
-    }
-
-    SECTION("compatible with std::transform (reverse iterator)") {
-        fixed_array_t arr;
-        {
-            const fixed_array_t arr1{"0000000", "1111111"};
-            std::copy(arr1.rbegin(), arr1.rend(), std::back_inserter(arr));
-        }
-        CHECK(arr.size() == 2);
-        CHECK(arr[0] == std::string("1111111"));
-        CHECK(arr[1] == std::string("0000000"));
-    }
-
-    SECTION("compatible with std::remove_copy_if") {
-        fixed_array_t arr2;
-        {
-            const fixed_array_t arr1{"0000000", "1111111"};
-            std::remove_copy_if(arr1.begin(),
-                                arr1.end(),
-                                std::back_inserter(arr2),
-                                [](const fixed_array_t::value_type& s) {
-                                    return std::strncmp(s.data(), "1111111", 7) == 0;
-                                });
-        }
-        CHECK(arr2.size() == 1);
-        CHECK(arr2[0] == std::string("0000000"));
-    }
-}
-
-TEST_CASE("HighFiveFixedLenStringArrayAttribute") {
-    const std::string file_name("fixed_array_attr.h5");
-    // Create a new file using the default property lists.
-    {
-        File file(file_name, File::ReadWrite | File::Create | File::Truncate);
-        FixedLenStringArray<10> arr{"Hello", "world"};
-        file.createAttribute("str", arr);
-    }
-    // Re-read it
-    {
-        File file(file_name);
-        FixedLenStringArray<8> arr;  // notice the output strings can be smaller
-        file.getAttribute("str").read(arr);
-        CHECK(arr.size() == 2);
-        CHECK(arr[0] == std::string("Hello"));
-        CHECK(arr[1] == std::string("world"));
-    }
-}
-
 TEST_CASE("HighFiveReference") {
     const std::string file_name("h5_ref_test.h5");
     const std::string dataset1_name("dset1");